限制并发线程的数量

假设有很多的下载需要处理。

var urls = new []{
	"https://..."
};
var client = new HttpClient();
foreach(var url in urls)
{
	var html = await client.GetStringAsync(url);
	
}

如果想并行处理的话,通常的做法是为每一个地址下载配上一个线程,然后等到所有线程处理结束。如果只想用4个线程呢?

var maxThreads=4;
//先把字符串放队列里
var q = new ConcurrentQueue<string>(urls);
var tasks = new List<Task>();
for(int n = 0; n < maxThreads;n++){
	task.Add(Task.Run(async ()=>{
		while(q.TryDequeue(out string url)){
			var html = await client.GetStringAsync(url);
		}
	}));
}
await Tas.WhenAll(tasks);

以上先把字符串放队列里,然后规定线程的数量,这个很好。但是,有可能遍历完线程之后,队列里还有数据没有读出来。

来看看下面的做法。

var maxThread = 4;
var allTasks = new List<Task>();
var throtter = new SemaphoreSlim(iniitalCount:maxThreads);
foreach(var url in urls)
{
	await throtter.WaitAsync();
	allTasks.Add(Task.Run(()=> {}
		try
		{
			var html = await client.GetStringAsync(url);
			
		}
		finally
		{
			throttler.Release();
		}
	));
}
await Task.WhenAll(allTasks);

还可以用Parallel.ForEach

var options = new PrallelOptions(){MaxDegreeOfParallelism = maxThreds};
Prallel.ForEach(urls, options, url => {
	var html = client.GetStringAsync(url).Result;
})

第三个参数是Action,只能是同步方法,如果想要使用异步方法,还有一个AsyncEnumerator这个NuGet组件可以用。

await uris.PralleForEachAsync(
	async url => {
		var html = await httpClient.GetStringAsync(url);
	}, maxDegreeOfParalellism:maxThreads
);

还有一种隔离策略,就是使用有限的并发数生成一个无限的排队队列。

var bulkhead = Policy.BulkheadAsync(maxThreds, Int32.MaxValue);
var tasks = new List<Task>();
foreach(var url in urls)
{
	var t = builkhead.ExecuteAsync(async () => {
		var html = await client.GetStringAsync(url);
	});
	tasks.Add(t);
}

await Task.WhenAll(tasks);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值