Task Parallel Library - Custom Task Schedulers

后端 未结 4 604
萌比男神i
萌比男神i 2021-02-06 12:35

I have a requirement to fire off web service requests to an online api and I thought that Parallel Extensions would be a good fit for my needs.

The web service in questi

4条回答
  •  别那么骄傲
    2021-02-06 13:15

    I agree with others that TPL Dataflow sounds like a good solution for this.

    To limit the processing, you could create a TransformBlock that doesn't actually transform the data in any way, it just delays it if it arrived too soon after the previous data:

    static IPropagatorBlock CreateDelayBlock(TimeSpan delay)
    {
        DateTime lastItem = DateTime.MinValue;
        return new TransformBlock(
            async x =>
                    {
                        var waitTime = lastItem + delay - DateTime.UtcNow;
                        if (waitTime > TimeSpan.Zero)
                            await Task.Delay(waitTime);
    
                        lastItem = DateTime.UtcNow;
    
                        return x;
                    },
            new ExecutionDataflowBlockOptions { BoundedCapacity = 1 });
    }
    

    Then create a method that produces the data (for example integers starting from 0):

    static async Task Producer(ITargetBlock target)
    {
        int i = 0;
        while (await target.SendAsync(i))
            i++;
    }
    

    It's written asynchronously, so that if the target block isn't able to process the items right now, it will wait.

    Then write a consumer method:

    static void Consumer(int i)
    {
        Console.WriteLine(i);
    }
    

    And finally, link it all together and start it up:

    var delayBlock = CreateDelayBlock(TimeSpan.FromMilliseconds(500));
    
    var consumerBlock = new ActionBlock(
        (Action)Consumer,
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
    
    delayBlock.LinkTo(consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });
    
    Task.WaitAll(Producer(delayBlock), consumerBlock.Completion);
    

    Here, delayBlock will accept at most one item every 500 ms and the Consumer() method can run multiple times in parallel. To finish processing, call delayBlock.Complete().

    If you want to add some caching per your #2, you could create another TransformBlock do the work there and link it to the other blocks.

提交回复
热议问题