欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

避免在C#循環(huán)中使用await的方法小結(jié)

 更新時間:2024年09月10日 11:40:51   作者:一個程序員_zhangzhen  
在C#中,異步編程因其能夠提升應用程序性能和響應能力而變得越來越流行,async和await關(guān)鍵字使得編寫異步代碼變得更加容易,但如果使用不當,它們也可能引入一些陷阱,所以本文我們將探討為什么應該避免在C#循環(huán)中使用await,并討論一些更高效地處理異步操作的替代方法

引言

在C#中,異步編程因其能夠提升應用程序性能和響應能力而變得越來越流行。async和await關(guān)鍵字使得編寫異步代碼變得更加容易,但如果使用不當,它們也可能引入一些陷阱。一個常見的錯誤是在循環(huán)中使用await,這可能導致性能瓶頸和意外行為。在本文中,我們將探討為什么應該避免在C#循環(huán)中使用await,并討論一些更高效地處理異步操作的替代方法。

一 在循環(huán)中使用await的問題

1、順序執(zhí)行

當在循環(huán)中使用await時,每次迭代都會等待前一次迭代完成后再開始。這導致了順序執(zhí)行,抵消了異步編程的好處。請看以下示例:

foreach (var item in items) 
{ 
    await ProcessItemAsync(item); 
}

在這段代碼中,每次迭代都會等待ProcessItemAsync完成后再進行下一次迭代。如果ProcessItemAsync需要較長時間才能完成,這會導致性能不佳。

示例場景

假設(shè)我們需要通過異步下載處理一組URL的內(nèi)容。在循環(huán)中使用await的代碼如下:

foreach (var url in urls) 
{ 
    var content = await DownloadContentAsync(url); 
    ProcessContent(content); 
}

在這種情況下,每個URL都是一個接一個地處理,導致總執(zhí)行時間是所有單個下載時間的總和。如果我們有10個URL,每個下載需要1秒,總執(zhí)行時間將大約是10秒。

2、資源爭用

在循環(huán)中使用await還可能導致資源爭用。每次迭代都會占用資源(如內(nèi)存和網(wǎng)絡(luò)連接)直到等待的任務(wù)完成。這可能導致可用資源的耗盡,尤其是在處理大量任務(wù)時。

二 更好的替代方法

1、使用Task.WhenAll

為了并發(fā)執(zhí)行異步操作,我們可以使用Task.WhenAll。這種方法允許我們一次啟動所有異步任務(wù),并等待它們?nèi)客瓿?。以下是如何重寫前面的示例?/p>

using System.Diagnostics;
using System.Net;
 
namespace ConsoleApp1
{
    public class Program
    {
        public async static Task Main(string[] args)
        {
            var urls = new List<string>
            {
                "https://www.163.com",
                "https://www.microsoft.com",
                "https://www.baidu.com"
            };
            Stopwatch sw = Stopwatch.StartNew();
            foreach (var url in urls)
            {
                var content = await DownloadContentAsync(url);
                ProcessContent(content);
            }
            Console.WriteLine($"foreach總共用時:{sw.Elapsed.TotalSeconds}秒");
            Stopwatch sw2 = Stopwatch.StartNew();
            var downloadTasks = urls.Select(url => DownloadContentAsync(url)).ToArray();
            var contents = await Task.WhenAll(downloadTasks);
            foreach (var content in contents)
            {
                ProcessContent(content);
            }
            Console.WriteLine($"WhenAll總共用時:{sw2.Elapsed.TotalSeconds}秒");
        }
        public async static Task<string> DownloadContentAsync(string url)
        {
            using (var client = new HttpClient(new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip }))
            {
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36");
                var response = await client.GetAsync(url);
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            }
        }
        public static void ProcessContent(string content)
        {
            Console.WriteLine($"處理內(nèi)容的長度: {content.Length}");// 這里可以添加更多的內(nèi)容處理邏輯  }
        }
    }
}

在這個版本中,所有下載任務(wù)同時啟動,我們等待它們?nèi)客瓿珊笤偬幚斫Y(jié)果。這種方法顯著減少了總執(zhí)行時間,因為任務(wù)是并行運行的。經(jīng)測驗,循環(huán)多少次,Task.WhenAll的速度比foreach的速度快大概多少倍!

2、使用Parallel.ForEachAsync

C#還提供了Parallel.ForEachAsync,它允許你在不阻塞主線程的情況下并行運行異步操作:

await Parallel.ForEachAsync(urls, async (url, cancellationToken) => 
{ 
    var content = await DownloadContentAsync(url); 
    ProcessContent(content); 
});

Parallel.ForEachAsync確保多個迭代可以并發(fā)運行,提升性能的同時保持代碼的簡潔和可讀性。

Parallel.ForEachAsync的運行效率與Task.WhenAll的效率差不多

3、限制并發(fā)

在某些情況下,運行過多的并發(fā)任務(wù)可能會使系統(tǒng)資源不堪重負。我們可以通過使用SemaphoreSlim來限制并發(fā)級別:

這個在執(zhí)行過程中產(chǎn)生了異常,等解決了在繼續(xù)討論

這種方法限制了并發(fā)任務(wù)的數(shù)量,更有效地管理資源使用。

三 結(jié)論

雖然await是C#異步編程的強大工具,但在循環(huán)中使用它可能導致性能不佳和資源爭用。通過理解順序執(zhí)行的影響,并利用Task.WhenAll、Parallel.ForEachAsync和SemaphoreSlim等替代方法,我們可以編寫更高效和健壯的異步代碼。避免在循環(huán)中使用await并采用更好的模式將提升你的應用程序性能,使代碼更易維護和擴展。遵循這些最佳實踐,你可以充分利用C#異步編程的潛力。

以上就是避免在C#循環(huán)中使用await的方法小結(jié)的詳細內(nèi)容,更多關(guān)于避免C#循環(huán)使用await的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論