【问题标题】:run console task asynchronously [closed]异步运行控制台任务[关闭]
【发布时间】:2013-08-25 14:46:03
【问题描述】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace NewTask
{
    class Program
    {
        static void Main(string[] args)
        {
            NewTask.Combine taskcombine = new NewTask.Combine();
            ProfileClient profilesws = new ProfileClient();
            var profileRecords = profilesws.GetAllProfiles();
            foreach (var profile in profileRecords.ProfileRecords)
            {
                var testProfile = new NewTask.Profile();
                testProfile.Id = profile.Id;
                testProfile.Name = profile.Name;


                var result = taskcombine.TestProfile(testProfile);

            }


            profilesws.Close();
            taskcombine.Close();
        }
    }
}

我想要一种方法来运行这个异步。我想打 ruslt,一旦它通过所有记录进入结果,我希望它结束​​任务。这将是一个 consol 应用程序,一旦结果填充了所需的记录,我希望它异步关闭应用程序。

【问题讨论】:

  • 你真的想要异步还是你真的在寻找并行?因为如果它是异步的,那么在任务运行时还要做哪些其他工作? taskcombine.TestProfile 可以安全地从多个线程运行吗?如果您什么都不做,为什么要返回结果?
  • 这与您的问题有何不同:stackoverflow.com/questions/18388419/…
  • 我不希望它等到它完成完整的循环。我希望它异步运行,一旦结果填充关闭应用程序,而不是等待其余部分。
  • 所以你只关心第一次迭代产生结果吗? TestProfile() 是否有返回 Task 的异步版本,还是您需要自己启动任务?
  • 是的,没错@ScottChamberlain 我只关心产生结果的第一次迭代,我将自己运行任务。

标签: c# .net


【解决方案1】:

如果 TestProfile 有一个 TestProfileAsync 版本返回一个 Task 你的代码将是

class Program
{
    static void Main(string[] args)
    {
        NewTask.Combine taskcombine = new NewTask.Combine();
        ProfileClient profilesws = new ProfileClient();
        var profileRecords = profilesws.GetAllProfiles();

        var tasks = new List<Task<ResultClass>>();

        foreach (var profile in profileRecords.ProfileRecords)
        {
            var testProfile = new NewTask.Profile();
            testProfile.Id = profile.Id;
            testProfile.Name = profile.Name;

            tasks.Add(taskcombine.TestProfileAsync(testProfile))
        }

        int completedIndex = Task.WaitAny(tasks.ToArray());

        var result = tasks[completedIndex].Result;

        profilesws.Close();
        taskcombine.Close();
    }
}

如果函数没有异步版本,您需要将其包装在您自己的任务中。

tasks.Add(Task<ResultClass>.Factory.Start(() => taskcombine.TestProfile(testProfile)));

这都是假设taskcombine.TestProfile 是线程安全的。如果它不是线程安全的,您需要解释更多 taskcombine.TestProfile 的作用以及是否可以创建多个实例

tasks.Add(Task<ResultClass>.Factory.Start(() => 
{
     NewTask.Combine taskcombine = new NewTask.Combine(); //Move the declaration inside the task so a new Combine gets created per task.
     return taskcombine.TestProfile(testProfile);
}));

编辑:您可以做的另一项调整是使用cancellation token,因此如果您在某些任务开始之前已经有结果,它们根本不会开始。

首先,使用具有签名 Task&lt;ResultClass&gt; TestProfileAsync(NewTask.Profile a, CancllationToken token) 的异步版本的 TestProfileAsync 的理想解决方案

class Program
{
    static void Main(string[] args)
    {
        NewTask.Combine taskcombine = new NewTask.Combine();
        ProfileClient profilesws = new ProfileClient();
        var profileRecords = profilesws.GetAllProfiles();

        var tasks = new List<Task<ResultClass>>();
        var cts = new CancellationTokenSource();
        var token = cts.Token;            

        foreach (var profile in profileRecords.ProfileRecords)
        {
            var testProfile = new NewTask.Profile();
            testProfile.Id = profile.Id;
            testProfile.Name = profile.Name;

            tasks.Add(taskcombine.TestProfileAsync(testProfile, token))
        }

        int completedIndex = Task.WaitAny(tasks.ToArray());

        //This should stop any tasks before they even start.
        cts.Cancel();

        var result = tasks[completedIndex].Result;

        profilesws.Close();
        taskcombine.Close();
    }
}

如果您无法访问异步版本,这里是带有任务的 4.5 版本代码

class Program
{
    static void Main(string[] args)
    {
        NewTask.Combine taskcombine = new NewTask.Combine();
        ProfileClient profilesws = new ProfileClient();
        var profileRecords = profilesws.GetAllProfiles();

        var tasks = new List<Task<ResultClass>>();
        var cts = new CancellationTokenSource();
        var token = cts.Token;            

        foreach (var profile in profileRecords.ProfileRecords)
        {
            var testProfile = new NewTask.Profile();
            testProfile.Id = profile.Id;
            testProfile.Name = profile.Name;

            //If the token is canceled before the task gets to start itself it should never start and go stright to the "Canceled" state.
            tasks.Add(Task.Run(() => 
                       {
                           token.ThrowIfCancellationRequested(); //In case the task started but we did get a result before the last 
                           return taskcombine.TestProfile(testProfile); //Assumes "taskcombine.TestProfile(...)" is thread safe.
                       }, token));
        }

        var result = Task.WhenAny(tasks).Result;

        //This should stop any tasks that have not spun up yet from spinning up
        cts.Cancel();

        profilesws.Close();
        taskcombine.Close();
    }
}

【讨论】:

  • 所有这些代码都使用 4.0 类。如果您使用的是 4.5,您可以执行 tasks.Add(Task.Run(() =&gt; taskcombine.TestProfile(testProfile)));Task.WhenAny(tasks).Result 之类的操作来简化代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多