Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一次阻止收集过程n个项目-完成1个后继续_C#_.net_Task Parallel Library_Async Await_Blockingcollection - Fatal编程技术网

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和一个

我有下面的场景

  • 我将数据库中的50个作业放入一个阻塞集合

  • 每个作业都是长期运行的。(可能是)。所以我想在一个单独的线程中运行它们。(我知道-最好将它们作为Task.whalll运行,并让TPL解决-但我想控制同时运行的次数)

  • 假设我想同时运行其中5个(可配置)

  • 我创建了5个任务(TPL),每个任务一个,并并行运行它们

  • 我想做的是,一旦步骤4中的一个作业完成,就开始执行阻塞集合中的下一个作业,并继续执行,直到所有50个作业都完成为止

    我正在考虑创建一个静态blockingCollection和一个TaskCompletionSource,当一个作业完成时将调用它,然后它可以再次调用使用者从队列中一次选择一个作业。我还想在每个作业上调用async/await,但最重要的是,我不确定这是否会对方法产生影响

    这是完成我想要做的事情的正确方法吗

    类似于link,但关键是我希望在前N项中的一项完成后立即处理下一个作业。不是所有的N都完成了

    更新:

    好的,如果以后有人想使用它,我会让这个代码片段完全按照我的要求执行。正如您在下面看到的,创建了5个线程,每个线程在使用当前线程完成后开始下一个作业。在任何给定时间只有5个线程处于活动状态。我知道这可能不会一直像这样100%工作,如果与一个cpu/核心一起使用,将有上下文切换的性能问题

    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(); }