我工作的公司運行幾百個非常動態的網站。它已經決定建立一個搜索引擎,我負責編寫刮板。有些網站運行在舊硬件上,無法承受很大的處罰,而其他網站可以同時處理大量用戶。.NET中的並行抓取
我需要能夠說爲站點A,2爲站點B和1使用5個平行請求站點C.
我知道可以使用線程,互斥,信號等來實現這一點,但它會相當複雜。任何更高級別的框架,比如TPL,都等待/異步,TPL Dataflow足夠強大,以更簡單的方式來完成這個應用程序?
我工作的公司運行幾百個非常動態的網站。它已經決定建立一個搜索引擎,我負責編寫刮板。有些網站運行在舊硬件上,無法承受很大的處罰,而其他網站可以同時處理大量用戶。.NET中的並行抓取
我需要能夠說爲站點A,2爲站點B和1使用5個平行請求站點C.
我知道可以使用線程,互斥,信號等來實現這一點,但它會相當複雜。任何更高級別的框架,比如TPL,都等待/異步,TPL Dataflow足夠強大,以更簡單的方式來完成這個應用程序?
我建議你使用HttpClient
與Task.WhenAll
,與SemaphoreSlim
簡單節流:
private SemaphoreSlim _mutex = new SemaphoreSlim(5);
private HttpClient _client = new HttpClient();
private async Task<string> DownloadStringAsync(string url)
{
await _mutex.TakeAsync();
try
{
return await _client.GetStringAsync(url);
}
finally
{
_mutex.Release();
}
}
IEnumerable<string> urls = ...;
var data = await Task.WhenAll(urls.Select(url => DownloadStringAsync(url));
或者,你可以使用TPL數據流,並設置爲MaxDegreeOfParallelism
節流。
TPL Dataflow
和async-await
確實功能強大,簡單到足以能正是你需要:
async Task<IEnumerable<string>> GetAllStringsAsync(IEnumerable<string> urls)
{
var client = new HttpClient();
var bag = new ConcurrentBag<string>();
var block = new ActionBlock<string>(
async url => bag.Add(await client.GetStringAsync(url)),
new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 5});
foreach (var url in urls)
{
block.Post(url);
}
block.Complete();
await block.Completion;
return bag;
}