对于并发异步 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 = { "https://google.com", "https://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 = { "https://google.com", "https://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
进行手动并发控制可能是更可靠的选择。
源代码获取:公众号回复消息【code:24490
】