异步编程并等待循环

时间:2013-01-17 14:49:10

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

我开始学习C#5和.Net 4.5中的异步编程,还有一些我不理解的东西。

private static int count;

public static void Main()
{
    LoopTest();

    Console.ReadKey(false);
}

static async void LoopTest()
{
    count = 0;

    for (var index = 0; index < 10; ++index)
    {
        Console.WriteLine( "({0}) In Loop before await, Index {1}, Thread: {2}", count++, index, Thread.CurrentThread.ManagedThreadId);
        await Task.Factory.StartNew(() => Thread.Sleep(10));
    }
}

结果是:

 (0) In Loop before await, Index 0, Thread: 9  
 (1) In Loop before await, Index 1, Thread: 10    
 (2) In Loop before await, Index 2, Thread: 11   
 (3) In Loop before await, Index 3, Thread: 10  
 (4) In Loop before await, Index 4, Thread: 11  
 (5) In Loop before await, Index 5, Thread: 10  
 (6) In Loop before await, Index 6, Thread: 12  
 (7) In Loop before await, Index 7, Thread: 11  
 (8) In Loop before await, Index 8, Thread: 10  
 (9) In Loop before await, Index 9, Thread: 12

那么有不同的线程访问同一个循环吗?索引变量上有Race-Condition吗?

2 个答案:

答案 0 :(得分:13)

不,没有竞争条件。您启动一个将在后台运行的新任务,但在该任务完成之前您的代码将不会继续,因此您可以确保您的代码在任何时候都只能在一个线程中执行。

但是,因为这是一个控制台应用程序,所以没有当前的SyncronizationContext。 (与winform,WPF,ASP,Silverlight等应用程序相对应。)这意味着来自任何await调用的延续将在线程池中运行,而不是在调用线程中运行。所以,是的,你在循环的每次迭代中都在一个线程池线程中运行,并且每次都可能是不同的,但你可以确定,除了你在新任务中放置的任何内容之外,你将“完成“在开始处理下一个线程之前在任何给定线程上运行,这确保在任何给定时间只有一个线程运行代码(这意味着没有竞争条件)。

答案 1 :(得分:4)

你所做的并不是真正的asycnhronous

await Task.Factory.StartNew(() => Thread.Sleep(10));

这将创建一个任务,然后等待该任务完成。你也可以在这里调用Thread.Sleep(10)。

更合适的方法是:

Task myTask = Task.Factory.StartNew(() => Thread.Sleep(10));
... do stuff here ...
await myTask; // Now wait for the task to complete

如果您想在循环中执行许多任务,您应该查看Parallel.Foreach()方法。