Throttling asynchronous tasks

后端 未结 3 440
心在旅途
心在旅途 2020-11-22 13:13

I would like to run a bunch of async tasks, with a limit on how many tasks may be pending completion at any given time.

Say you have 1000 URLs, and you only want to

3条回答
  •  花落未央
    2020-11-22 13:32

    As suggested, use TPL Dataflow.

    A TransformBlock may be what you're looking for.

    You define a MaxDegreeOfParallelism to limit how many strings can be transformed (i.e., how many urls can be downloaded) in parallel. You then post urls to the block, and when you're done you tell the block you're done adding items and you fetch the responses.

    var downloader = new TransformBlock(
            url => Download(url),
            new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 50 }
        );
    
    var buffer = new BufferBlock();
    downloader.LinkTo(buffer);
    
    foreach(var url in urls)
        downloader.Post(url);
        //or await downloader.SendAsync(url);
    
    downloader.Complete();
    await downloader.Completion;
    
    IList responses;
    if (buffer.TryReceiveAll(out responses))
    {
        //process responses
    }
    

    Note: The TransformBlock buffers both its input and output. Why, then, do we need to link it to a BufferBlock?

    Because the TransformBlock won't complete until all items (HttpResponse) have been consumed, and await downloader.Completion would hang. Instead, we let the downloader forward all its output to a dedicated buffer block - then we wait for the downloader to complete, and inspect the buffer block.

提交回复
热议问题