29

我将如何构造下面的代码以便调用异步方法?

Parallel.For(0, elevations.Count(), delegate(int i)
{
   allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
4

4 回答 4

44

Parallel.For()不适用于async方法。如果您不需要限制并行度(即您可以同时执行所有任务),您可以简单地启动所有Tasks 然后等待它们完成:

var tasks = Enumerable.Range(0, elevations.Count())
    .Select(i => BuildSheetsAsync(userID, elevations[i], includeLabels));
List<Bitmap> allSheets = (await Task.WhenAll(tasks)).SelectMany(x => x).ToList();
于 2013-10-10T09:50:40.233 回答
4

我建议你看看我几天前问的这个问题,最后回答了自己,基本上我在寻找一个并行和异步的 ForEach 方法

该方法用于SemaphoreSlim并行处理事物,它接受异步方法作为输入操作。

您可能还想查看我在答案末尾提供的两个链接,它们对于实现这种行为非常有帮助,并且它们还包含另一种使用 aPartitioner来执行此操作的方法。

就个人而言,我不喜欢它,Parallel.For因为它是我给出的链接中解释的同步调用;我想要这一切'异步':-)

这里是:异步和并行下载文件

于 2013-10-09T23:10:27.613 回答
4

你可以试试我正在使用的这段代码。它使用 foreach 和 SemaphoreSlim 来实现并行异步。

public static class ParallelAsync
{
    public static async Task ForeachAsync<T>(IEnumerable<T> source, int maxParallelCount, Func<T, Task> action)
    {
        using (SemaphoreSlim completeSemphoreSlim = new SemaphoreSlim(1))
        using (SemaphoreSlim taskCountLimitsemaphoreSlim = new SemaphoreSlim(maxParallelCount))
        {
            await completeSemphoreSlim.WaitAsync();
            int runningtaskCount = source.Count();

            foreach (var item in source)
            {
                await taskCountLimitsemaphoreSlim.WaitAsync();

                Task.Run(async () =>
                {
                    try
                    {
                        await action(item).ContinueWith(task =>
                        {
                            Interlocked.Decrement(ref runningtaskCount);
                            if (runningtaskCount == 0)
                            {
                                completeSemphoreSlim.Release();
                            }
                        });
                    }
                    finally
                    {
                        taskCountLimitsemaphoreSlim.Release();
                    }
                }).GetHashCode();
            }

            await completeSemphoreSlim.WaitAsync();
        }
    }
}

用法:

string[] a = new string[] {
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15",
    "16",
    "17",
    "18",
    "19",
    "20"
};

Random random = new Random();

await ParallelAsync.ForeachAsync(a, 2, async item =>
{
    Console.WriteLine(item + " start");

    await Task.Delay(random.Next(1500, 3000));
    Console.WriteLine(item + " end");
});

Console.WriteLine("All finished");

任何建议请告诉我。

于 2019-10-15T05:01:28.947 回答
-6

在内部调用异步方法的最简单方法Parallel.For是:

Parallel.For(0, elevations.Count(), async i =>
{
   allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});

===============

MarioDS在评论中绝对正确地提到,在这种情况下,您可能会有未观察到的异常。这绝对是非常重要的事情,您应该始终牢记这一点,然后处理异步委托。

在这种情况下,如果您认为您会遇到异常,您可以try/catch在委托中使用块。或者在某些情况下,如果您的情况适合,您可以订阅TaskScheduler.UnobservedTaskException事件。

于 2016-02-29T06:37:40.443 回答