将参数传递给异步函数

时间:2018-04-04 15:22:46

标签: c# async-await

很抱歉,如果之前有人询问过。 我有两个几乎相同的函数sync和async:

    private static void runLong(int id)
    {
        Console.WriteLine("starting " + id );
        Thread.Sleep(myRandom.Next(200,1000));
        Console.WriteLine("-exiting " + id);
    }
    private static async Task runLongAsync(int id)
    {
        Console.WriteLine("starting " + id );
        await Task.Run(()=>Thread.Sleep(myRandom.Next(200,1000)));
        Console.WriteLine("-exiting " + id );
    }

我以非常类似的方式打电话给他们:

    public static void run()
    {
            run().Wait();
            runAsync().Wait();
    }
    private static async Task run()
    {
        List<Task> runningTasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            runningTasks.Add(Task.Run(() => runLong(i)));  
        }
        await Task.WhenAll(runningTasks);
    }
    private static async Task runAsync()
    {
        List<Task> runningTasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            runningTasks.Add(runLongAsync(i));   
        }
        await Task.WhenAll(runningTasks);
    }

但结果不同: 异步调用同步函数

  • 从5开始
  • 从5开始
  • 从5开始
  • 从5开始
  • 从5开始
  • 退出5
  • 退出5
  • 退出5
  • 退出5
  • 退出5

调用异步函数:

  • 从0开始
  • 开始1
  • 开始2
  • 开始3
  • 开始4
  • 退出0
  • 退出3
  • 退出2
  • 退出1
  • 退出4

即。在第一种情况下,参数被覆盖,但在第二种情况下 - 它们不是。这是怎么回事?

Edit1:是的我找到了一个快速修复 int copy = i; 但我想了解这里实际发生了什么以及为什么这两个函数的行为不同。

Edit2:@Servy引用的文章解释了为什么 for foreach 循环的行为不同,在我的情况下我有两个 for 循环表现不同

1 个答案:

答案 0 :(得分:0)

捕获的变量。每个循环迭代i此处,因此它会在启动时获取当前值 - 这可能是5

for (int i = 0; i < 5; i++)
{
    runningTasks.Add(Task.Run(() => runLong(i)));  
}

解决方法是在循环内提​​升值:

for (int i = 0; i < 5; i++)
{
    var j = i;
    runningTasks.Add(Task.Run(() => runLong(j)));  
}

这里重点是j现在在循环中 ,因此捕获的变量上下文特定于该迭代。