概述:通過使用`SemaphoreSlim`,可以簡單而有效地限制非同步HTTP請求的併發量,確保在任何給定時間內不超過20個網頁同時下載。`ParallelOptions`不適用於非同步操作,但可考慮使用`Parallel.ForEach`,儘管在非同步場景中謹慎使用。 對於併發非同步 I/O 操作的數量 ...
概述:通過使用`SemaphoreSlim`,可以簡單而有效地限制非同步HTTP請求的併發量,確保在任何給定時間內不超過20個網頁同時下載。`ParallelOptions`不適用於非同步操作,但可考慮使用`Parallel.ForEach`,儘管在非同步場景中謹慎使用。
對於併發非同步 I/O 操作的數量限制,可以使用SemaphoreSlim,但由於AsParallel 使用的是 PLINQ(Parallel LINQ),而 PLINQ 不太適用於非同步操作。因此,我們可以使用非同步的 Task.WhenAll 和 SemaphoreSlim 來實現併發控制。同時,ParallelOptions 不適用於非同步操作,因為它主要用於同步的 Parallel 類庫。
以下是一個使用 SemaphoreSlim 的示例,以確保在任何給定時間下載的網頁不超過 20 個:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string[] urls = { "http://google.com", "http://yahoo.com", /*...*/ };
// 設置最大併發數為20
int maxConcurrency = 20;
var semaphore = new SemaphoreSlim(maxConcurrency);
var tasks = urls.Select(url => DownloadUrlAsync(url, semaphore));
await Task.WhenAll(tasks);
}
static async Task DownloadUrlAsync(string url, SemaphoreSlim semaphore)
{
await semaphore.WaitAsync();
try
{
var client = new HttpClient();
var html = await client.GetStringAsync(url);
// 處理獲取的 HTML 數據
Console.WriteLine($"Downloaded {url} successfully");
}
catch (Exception ex)
{
// 處理異常
Console.WriteLine($"Error downloading {url}: {ex.Message}");
}
finally
{
semaphore.Release();
}
}
}
在這個例子中,SemaphoreSlim 用於限制併發非同步 I/O 操作的數量。WaitAsync 方法用於獲取信號,Release 方法用於釋放信號。這確保了在任何給定時間內,同時運行的非同步操作數量不會超過 maxConcurrency 指定的最大併發數。
如果你想使用 ParallelOptions,你可以考慮使用 Parallel.ForEach,但要註意這仍然適用於同步操作。以下是一個示例:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
string[] urls = { "http://google.com", "http://yahoo.com", /*...*/ };
// 設置最大併發數為20
int maxConcurrency = 20;
Parallel.ForEach(urls, new ParallelOptions { MaxDegreeOfParallelism = maxConcurrency }, async (url) =>
{
var client = new HttpClient();
var html = await client.GetStringAsync(url);
// 處理獲取的 HTML 數據
Console.WriteLine($"Downloaded {url} successfully");
});
}
}
上述代碼使用的 Parallel.ForEach 並不能直接處理非同步委托,因此需要謹慎使用。在非同步場景中,使用 SemaphoreSlim 進行手動併發控制可能是更可靠的選擇。