【问题标题】:Task.Run does not work like Thread.startTask.Run 不像 Thread.start 那样工作
【发布时间】:2018-07-16 06:35:58
【问题描述】:

我一直在开发一个应用程序,我需要以并行方式而不是阻塞方式运行一些方法。首先我使用了 Task.Run,但在 IN DEBUG MODE 中,我看到操作阻塞并等待结果。我不想要这个,我想要在 foreach 循环中调用的所有方法异步运行。

public async void f()
{
    foreach (var item in childrenANDparents)
    {
        await Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr));
        // foreach loop does not work until the task return and continues
    }
}

所以我将 task.run 更改为 thread.start,效果很好!

public async void f()
{
    foreach (var item in childrenANDparents)
    {
        Thread t = new Thread(() => SendUpdatedSiteInfo(item.Host, site_fr));
        t.Start();
        // foreach loop  works regardless of the method, in debug mode it shows me 
        // they are working in parallel
    }
}

你能解释一下有什么区别吗?为什么?我期望两个代码的行为相同,而且它们似乎不同。

谢谢

【问题讨论】:

  • await 确实如其所说,等待比赛
  • 哦,我不知道,我只是认为它是异步运行的,所以如果它等待它不能并行?我如何通过任务执行它?
  • 这需要Parallel.ForEach(),而不是await Task.Run()。 await 阻止了你。
  • 所以我误解了 async await 的概念,
  • 它将异步运行,但只到下一次等待。因此,如果您想同时异步运行一个方法,您可以使用var foo = Task.Run(() => Foo()); Bar(); await foo;。现在 Foo 与 Bar 并肩运行并在 await 处重新同步。话虽如此,如果您想并行运行多个东西,请使用 Parallel.For/ForEach 它将找到要使用的适当数量的线程,甚至在不同负载的情况下相应地调整它们。

标签: c# multithreading task


【解决方案1】:

我希望在 foreach 循环中调用的所有方法异步运行。

您似乎将异步/同步调用与并行化混淆了。

引用自 MSDN:

数据并行:并行处理的一种形式,其中相同的 计算在不同的数据上并行执行。数据并行 在 Microsoft .NET Framework 中由 Parallel.For 和 Parallel.ForEach 方法和 PLINQ。与任务并行性进行比较。

异步操作:不阻塞当前线程的操作 操作开始时的控制权。

让我们再仔细看看你的代码:

foreach (var item in childrenANDparents)
{
    await Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr));
}

await 关键字将导致编译器创建一个处理方法执行的 StateMachine。

就像你对编译器说:“在不阻塞任何线程的情况下开始这个异步操作,当它完成时 - 执行其余的东西”。

Task 完成执行后,该线程将被释放并返回到 ThreadPool,它将在 ThreadPool 中的第一个可用线程上执行其余代码,并尝试在它已启动的线程中执行它方法执行(除非使用 .ConfigureAwait(false) 在这种情况下,当我们并不真正关心哪个线程将继续执行时,它更像是“即发即弃”模式)。

当您创建一个单独的Thread 时,您可以通过委派一些代码在单独的线程中运行来实现并行性。因此,取决于代码本身,它可能会或可能不会被异步执行

就像你对编译器说:“把这件工作开始一个新线程并在那里做”

如果您仍然想使用具有并行性的任务,您可以在循环中创建一个任务数组,然后等待所有任务完成执行:

var tasks = new[] 
{ 
    childrenANDparents.Select(item=> Task.Run(() => SendUpdatedSiteInfo(item.Host,site_fr)));
}

await Task.WhenAll(tasks);

附言

是的,您也可以使用TPL(任务并行库),特别是并行循环。

【讨论】:

    【解决方案2】:

    您可以使用简单的Parallel.ForEachPLinq

    Parallel.ForEach(childrenANDparents, (item) => 
                                {
                                   SendUpdatedSiteInfo(item.Host,site_fr)
                                });
    

    为了更好地理解asyncawait,最好开始阅读一些文档,这是一个很大的话题,但值得您花时间

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 2012-05-27
      相关资源
      最近更新 更多