並行執行異步方法的最佳實踐

前言

最近寫了三篇關於並行異步的博客,因爲我走了很多彎路。

並行執行異步方法並接收返回值這個問題,stackoverflow上討論好幾年,.NET 6實現了Parallel.ForeachAsync。https://stackoverflow.com/questions/15136542/parallel-foreach-with-asynchronous-lambda

.NET 6 中的 API Parallel.ForEachAsync 在官方的博客中一直被忽略,但是我覺得這個 API 非常的實用!(這句話參考了博客:https://blog.csdn.net/sD7O95O/article/details/117914853)

要求

  1. 必須接收處理返回值

示例1

示例2

代碼說明

  1. 上述代碼我覺得非常優雅,java是無法優雅地寫出來的,會很難閱讀和維護。java19也許可以。
  2. 使用場景:普通的增刪改查功能估計是用不到,但我用到了。
  3. 上述代碼的並行度,可以根據es集羣的性能和吞吐量以及具體需求,進行合理的調整。

可以複製的代碼

上述代碼是圖片不方便複製,可以複製的代碼在 探索:優雅地實現異步方法的並行執行 文章的最後。

簡單的示例Demo代碼

private async void button4_Click(object sender, EventArgs e)
{
    await Task.Run(async () =>
    {
        Log($"==== 並行異步 開始,線程ID={Thread.CurrentThread.ManagedThreadId} ========================");
        Stopwatch sw = Stopwatch.StartNew();
        HttpClient httpClient = HttpClientFactory.GetClient();
        var tasks = new Dictionary<string, Task<Dictionary<int, int>>>();
        ConcurrentQueue<string> strs = new ConcurrentQueue<string>();

        await Parallel.ForEachAsync(Enumerable.Range(0, m), new ParallelOptions() { MaxDegreeOfParallelism = 100 }, async (i, c) =>
        {
            int sum = 0;
            await Parallel.ForEachAsync(Enumerable.Range(0, n), new ParallelOptions() { MaxDegreeOfParallelism = 30 }, async (j, c) =>
            {
                Dictionary<int, int> dict = await RequestAsync(_url, i);
                if (dict.ContainsKey(j))
                {
                    int num = dict[j];
                    Interlocked.Exchange(ref sum, sum + num);
                    strs.Enqueue($"{num}");
                }
            });
            Log($"輸出:sum={sum}");
        });

        Log($"輸出:{string.Join(",", strs.ToArray())}");
        sw.Stop();
        Log($"==== 結束,線程ID={Thread.CurrentThread.ManagedThreadId},耗時:{sw.Elapsed.TotalSeconds:0.000}秒 ========================");
    });
}

上述代碼說明

代碼中 Parallel.ForEachAsync(Enumerable.Range(0, m),... 代替了for循環。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章