C# 如何将唯一字符串传递给异步方法?

C# How to pass unique string to async method?

我正在创建多个线程,将不同的数据传递给每个线程。 但是,在 CallAsync 方法中,我有时会收到相同的数据。

为什么输入输出数据不同?

如何正确地将唯一字符串传递给每个线程?

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace NTest
{
    class Program
    {
        static async Task<int> CallAsync(string str)
        {
            Console.WriteLine("income: {0}", str);
            // await ...
            return 0;
        }

        static async void WorkerMainAsync()
        {
            List<Task> trackedTasks = new List<Task>();

            int[] jobs = new int[] { 0,1,2,3,4,5 };

            string str;

            foreach (int num in jobs)
            {
                str = num.ToString();
                Console.WriteLine("pass: {0}", str);
                trackedTasks.Add(Task.Run(() => CallAsync(str)));
            }
            await Task.WhenAll(trackedTasks);

            Console.WriteLine("[*] All jobs finished.");
        }

        static void Main(string[] args)
        {
            WorkerMainAsync();
            Console.ReadLine();
        }
    }
}

控制台输出:

pass: 0
pass: 1
pass: 2
income: 1
income: 2
pass: 3
pass: 4
income: 4
income: 4
income: 4
pass: 5
income: 5
[*] All jobs finished.

这与方法是异步的事实没有任何关系。

此行为是因为 lambda 表达式关闭变量,而不是值。所以表达式 () => CallAsync(str) 总是引用相同的 str 变量,最终在所有调用之间共享。

一个简单的解决方法是在循环内声明变量,这样每个 lambda 闭包都有自己的变量:

int[] jobs = new int[] { 0,1,2,3,4,5 };

foreach (int num in jobs)
{
  var str = num.ToString();
  Console.WriteLine("pass: {0}", str);
  trackedTasks.Add(Task.Run(() => CallAsync(str)));
}

await Task.WhenAll(trackedTasks);