Task.Run不能像Thread.start一样工作

时间:2018-07-16 06:35:59

标签: c# multithreading task

我一直在开发一个应用程序,我需要以并行而不是阻塞的方式运行一些方法。首先,我使用了 Task.Run ,但是在调试模式下,我看到该操作阻塞了,只是在等待结果。我不希望这样,我希望在 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
    }
}

请您说明有什么区别以及为什么吗?我期望这两个代码具有相同的行为,并且看起来它们是不同的。

谢谢

2 个答案:

答案 0 :(得分:4)

您可以使用简单的Parallel.ForEachPLinq

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

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

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

答案 1 :(得分:3)

  

我希望在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);

P.S。

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