C# 一次阻止收集过程n个项目-完成1个后继续
我有下面的场景C# 一次阻止收集过程n个项目-完成1个后继续,c#,.net,task-parallel-library,async-await,blockingcollection,C#,.net,Task Parallel Library,Async Await,Blockingcollection,我有下面的场景 我将数据库中的50个作业放入一个阻塞集合 每个作业都是长期运行的。(可能是)。所以我想在一个单独的线程中运行它们。(我知道-最好将它们作为Task.whalll运行,并让TPL解决-但我想控制同时运行的次数) 假设我想同时运行其中5个(可配置) 我创建了5个任务(TPL),每个任务一个,并并行运行它们 我想做的是,一旦步骤4中的一个作业完成,就开始执行阻塞集合中的下一个作业,并继续执行,直到所有50个作业都完成为止 我正在考虑创建一个静态blockingCollection和一个
var block = new ActionBlock<Job>(
job => Handler.HandleJob(job),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 });
foreach (Job j in GetJobs())
block.SendAsync(j);
var block=新动作块(
作业=>Handler.HandleJob(作业),
新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=5});
foreach(GetJobs()中的作业j)
block.SendAsync(j);
作业2从线程13开始。等待时间:3600000ms。时间:2014年8月29日
下午3:14:43
作业4从线程14开始。等待时间:15000ms。时间:2014年8月29日
下午3:14:43
作业0已在线程7上启动。等待时间:600000毫秒。时间:2014年8月29日
下午3:14:43
作业1已在线程12上启动。等待时间:900000毫秒。时间:2014年8月29日
下午3:14:43
作业3从线程11开始。等待时间:120000ms。时间:2014年8月29日
下午3:14:43
作业4在线程14上完成。2014年8月29日下午3:14:58
作业5在线程14上开始。等待时间:1800000ms。时间:2014年8月29日
下午3:14:58
作业3在线程11上完成。2014年8月29日下午3:16:43
作业6从线程11开始。等待时间:1200000毫秒。时间:2014年8月29日
下午3:16:43
线程7上的作业0已完成。2014年8月29日下午3:24:43
作业7已在线程7上启动。等待时间:30000ms。时间:2014年8月29日3:24:43
首相
作业7在线程7上完成。2014年8月29日下午3:25:13
作业8在线程7上启动。等待时间:100000毫秒。时间:2014年8月29日
下午3:25:13
作业8在线程7上完成。2014年8月29日下午3:26:53
作业9在线程7上启动。等待时间:900000毫秒。时间:2014年8月29日
下午3:26:53
作业1在线程12上完成。2014年8月29日下午3:29:43
作业10从线程12开始。等待时间:300000毫秒。时间:2014年8月29日
下午3:29:43
作业10在线程12上完成。2014年8月29日下午3:34:43
作业11在线程12上启动。等待时间:600000毫秒。时间:2014年8月29日
下午3:34:43
作业6在线程11上完成。2014年8月29日下午3:36:43
作业12在线程11上启动。等待时间:300000毫秒。时间:2014年8月29日
下午3:36:43
作业12在线程11上完成。2014年8月29日下午3:41:43
作业13从线程11开始。等待时间:100000毫秒。时间:2014年8月29日
下午3:41:43
作业9在线程7上完成。2014年8月29日下午3:41:53
作业14已在线程7上启动。等待时间:300000毫秒。时间:2014年8月29日
下午3:41:53
作业13在线程11上完成。2014年8月29日下午3:43:23
作业11在线程12上完成。2014年8月29日下午3:44:43
作业5在线程14上完成。2014年8月29日下午3:44:58
作业14在线程7上完成。2014年8月29日下午3:46:53
作业2在线程13上完成。2014年8月29日下午4:14:43
您可以使用中的
信号量lim
或使用中的ForEachAsync
来实现这一点。您可以轻松实现所需的功能
您所能做的是使用,这是一个用于存储数据的缓冲区,并将其与一个链接在一起,该链接将在这些请求从缓冲块
传入时使用这些请求
现在,这里的美妙之处在于,您可以指定希望ActionBlock
使用该类并发处理多少请求
这里是一个简化的控制台版本,它在输入一组数字时处理它们,打印它们的名称并Thread.ManagedThreadID
:
private static void Main(string[] args)
{
var bufferBlock = new BufferBlock<int>();
var actionBlock =
new ActionBlock<int>(i => Console.WriteLine("Reading number {0} in thread {1}",
i, Thread.CurrentThread.ManagedThreadId),
new ExecutionDataflowBlockOptions
{MaxDegreeOfParallelism = 5});
bufferBlock.LinkTo(actionBlock);
Produce(bufferBlock);
Console.ReadKey();
}
private static void Produce(BufferBlock<int> bufferBlock)
{
foreach (var num in Enumerable.Range(0, 500))
{
bufferBlock.Post(num);
}
}
private static void Main(字符串[]args)
{
var bufferBlock=新的bufferBlock();
var动作块=
新的ActionBlock(i=>Console.WriteLine(“读取线程{1}中的编号{0}”),
i、 Thread.CurrentThread.ManagedThreadId),
新的ExecutionDataflowBlockOptions
{MaxDegreeOfParallelism=5});
bufferBlock.LinkTo(actionBlock);
产生(缓冲块);
Console.ReadKey();
}
专用静态无效生成(缓冲块缓冲块)
{
foreach(可枚举范围(0500)中的var num)
{
bufferBlock.Post(num);
}
}
如果需要,您还可以使用可等待的
通过这种方式,您可以让
TPL
为您处理所有节流,而无需手动操作。您可以使用BlockingCollection
,它可以正常工作,但它是在async Wait
之前构建的,因此它可以同步阻塞,而在大多数情况下,它的可伸缩性可能较低。private static void Main()
{
var block = new ActionBlock<Job>(
async job => await job.ProcessAsync(),
new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 5});
for (var i = 0; i < 50; i++)
{
block.Post(new Job());
}
Console.ReadKey();
}