在异步 lambda 表达式中使用 await 运算符时出错



我正在尝试使用 Parallel.For 和异步等待将一些任意 GPS 数据(1.5 亿条记录)加载到 Azure 表存储中。但是我在第一个等待语句中收到以下错误:

"await"运算符只能在异步 lambda 表达式中使用。考虑使用"异步"修饰符标记此 lambda 表达式。

这是我的代码:

private static async Task GenerateGpsPointsForTruckAsync(int counter, CloudTableClient tableClient)
    {
        // Create a dummy VIN
        string vin = counter.ToString("D17");
        Random random = new Random();
        DateTime start = new DateTime(2010, 1, 1);
        int range = (DateTime.Today - start).Milliseconds;
        // Create the batch operation.
        TableBatchOperation batchOperation = new TableBatchOperation();
        // Prepare 10 batches of 100 GPS points
        Parallel.For(0, 10, i =>
        {
            for (int j = 0; j < 99; j++)
            {
                Location location = new Location(vin, start.AddDays(random.Next(range)).ToString());
                location.Coordinates = new GeoCoordinate(random.Next(30, 45), random.Next(75, 100));
                batchOperation.Insert(location);
            }
            await Task.Run(async () => 
            { 
                await LoadGpsPointsForTruckAsync(tableClient, batchOperation); 
            });
        });
    }

查看了一些关于堆栈溢出的解决方案,但它们似乎对我不起作用。

你不能

Parallel.For中使用 async-await,因为它比 async 旧并且不等待它(你可能也不想)。

如果要创建在线程池上运行的多个任务,可以通过多次调用Task.Run Task.WhenAll来完成,以便await完成所有任务:

await Task.WhenAll(Enumerable.Range(0,10).Select(i => Task.Run(() => Foo(i))));

当操作是同步的时,这是合适的。如果它是异步的,则不应将其卸载到线程池,除非您有理由这样做。您可以简单地调用该方法并等待结果:

await Task.WhenAll(Enumerable.Range(0,10).Select(i => FooAsync(i)));

Parallel.For希望您也将其 lambda 标记为 async,因为您的外部await Task.Run

Parallel.For(0, 10, async () => /* code */)

但是,async-await不能很好地与Parallel配合使用,因为它通过Action委托将其 lambda 转换为async void

似乎LoadGpsPointsForTruckAsync本身是异步的,您可以节省并行循环:

var coordinateTasks = Enumerable.Range(0, 100).Select(_ => 
            {
                Location location = new Location(vin, 
                                    start.AddDays(random.Next(range))
                                    .ToString())
                {
                   Coordinates = new GeoCoordinate(random.Next(30, 45),
                                                   random.Next(75, 100));
                }
                batchOperation.Insert(location);
                return LoadGpsPointsForTruckAsync(tableClient, batchOperation); 
            }
await Task.WhenAll(coordinateTasks);

最新更新