【问题标题】:Run two task asynchronously异步运行两个任务
【发布时间】:2015-01-29 10:46:41
【问题描述】:

我正在运行同步方法。在里面我必须运行两个大方法,所以我想异步运行它们。我在想类似的东西

public void MyFunc()
{
    var doWorkTask_1 = DoWork1();
    var doWorkTask_2 = DoWork2();

    var result1 = await doWorkTask_1;
    var result2 = await doWorkTask_2;

    if(result1 == result2) 
       ....

    Thread.Sleep(syncInterval);
}

为此,我需要:

  1. DoWork1DoWork2 是异步的;
  2. MyFunc 也是异步的;

但是没有方法是异步的!!!

所以我尝试了另一种方式:

public void MyFunc()
{
    var doWorkTask_1 = Task.Run(() => DoWork1());
    var doWorkTask_2 = Task.Run(() => DoWork2());

    var result1 = doWorkTask_1.Result;
    var result2 = doWorkTask_2.Result;

    if(result1 == result2) 
       ....

    Thread.Sleep(syncInterval);
}

所以,第一个问题: 我用两种不同的方式写过同样的东西吗?

第二个问题。我必须每X次运行MyFunc方法,所以我这样称呼它:

Task.Factory.StartNew(MyFunc);

我可以简单地称呼它吗

MyFunc();

我的问题是因为在myFunc 里面我有一个Thread.Sleep。我可以让主线程休眠还是让主线程休眠更好?

我希望我已经清楚了。 谢谢。

【问题讨论】:

  • 你能让MyFunc异步吗?还是必须同步?
  • 我更喜欢让它同步,因为如果我执行 MyFunc async,我还必须执行调用 MyFunc async 的方法,等等......

标签: c# .net multithreading asynchronous async-await


【解决方案1】:

我用两种不同的方式写过同样的东西吗?

没有。您的第一个方法将并行执行两个工作单元,并且将异步等待第一个,然后是第二个。

您的第二种方法将并行执行两个工作单元,并同步等待第一个,然后是第二个。

我可以让主线程休眠还是让线程休眠更好 在主里面?

这取决于您的应用程序在做什么。您可以将MyFunc 变成async,这样您就可以改用Task.Delay,它在内部使用一个定时器并且不会阻塞(如果需要,您也可以传递一个CancellationToken ):

public async Task MyFuncAsync()
{
   // Do work

   await Task.Delay(syncInterval);
}

旁注:

在我看来,您可能正在使用 异步而不是同步which in general is a questionable approach。我建议不要这样做。

相反,就像在您的第一个示例中一样,在这些工作人员上显式调用 Task.Run

public async Task MyFuncAsync()
{
    var firstTask = Task.Run(() => DoWork1());
    var secondTask = Task.Run(() => DoWork2());

    await Task.WhenAll(new[] { firstTask, secondTask });
    await Task.Delay(syncInterval);
}

【讨论】:

  • 我不能在 Task.Run 中有匿名函数吗?我怎么能打电话给 MyFuncAsync ???简单的 MyFuncAsync();还是 Task.Factory.StartNew(MyFuncAsync) ??
  • @Ciccio 我不确定你的意思。你可以Task.Run 中拥有一个匿名函数。如何拨打MyFuncAsyncawait MyFuncAsync();
  • @Cicco 你是对的。这就是为什么异步是一直,从堆栈的顶部到底部。为什么会有这样的问题?
  • @Ciccio 不,你不能。但是你可以使用Initialize pattern
  • @Ciccio 那么你会被阻止。这可能会导致死锁。我建议你不要。
【解决方案2】:

使用Task.WhenAll 创建一个新任务,封装您的两个工作任务。

创建一个将在所有提供的任务都完成时完成的任务 完成。

https://msdn.microsoft.com/en-us/library/hh194874%28v=vs.110%29.aspx

public async void MyFunc()
{
    var doWorkTask_1 = DoWork1();
    var doWorkTask_2 = DoWork2();

    var results = await Task.WhenAll(doWorkTask_1, doWorkTask_2);
}

【讨论】:

  • 但您还需要使 MyFunc 异步,这显然是 OP 不想做的
  • @NedStoyanov 我犯这个错误的频率让编译器开始嘲笑我..
  • 你的意思是var doWorkTask_1 = new Task( () => { DoWork1();}); ??
  • @Gusdor 我经常犯同样的错误。所以我认为应该弹出一个警告:)
【解决方案3】:

如果您不能一直执行async,并且异步意味着您想在不同线程上同时处理DoWork1DoWork2,那么您可以使用Task.Run 将工作卸载到一个不同的线程和Task.WaitAll同步等待两个任务完成:

public void MyFunc()
{
    var task1 = Task.Run(() => DoWork1());
    var task2 = Task.Run(() => DoWork2());

    Task.WaitAll(task1, task2);
    if (task1.Result == task2.Result)
    {
        // ...
    }

    Thread.Sleep(syncInterval);
}

现在,由于这使用了 3 个线程(Task.Run 中的两个 ThreadPool 线程和在 Task.WaitAll 上阻塞的调用线程)当我们只需要 2 个时,我们可以通过在调用线程:

public void MyFunc()
{
    var task1 = Task.Run(() => DoWork1());
    var result2 = DoWork2();

    if (task1.Result == result2)
    {
        // ...
    }

    Thread.Sleep(syncInterval);
}

【讨论】:

    猜你喜欢
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2018-09-12
    • 2020-06-08
    • 1970-01-01
    • 2015-07-18
    相关资源
    最近更新 更多