Why does cancellation block for so long when cancelling a lot of HTTP requests?

假装没事ソ 提交于 2019-11-30 15:26:47

Performing the CancellationTokenSource.Cancel() method call in a non-UI thread. This didn't work too well; the task didn't actually run until most of the others had finished.

What this tells me is that you're probably suffering from 'threadpool exhaustion', which is where your threadpool queue has so many items in it (from HTTP requests completing) that it takes a while to get through them all. Cancellation probably is blocking on some threadpool work item executing and it can't skip to the head of the queue.

This suggests that you do need to go with option 1 from your consideration list. Throttle your own work so that the threadpool queue remains relatively short. This is good for app responsiveness overall anyway.

My favorite way to throttle async work is to use Dataflow. Something like this:

var block = new ActionBlock<Uri>(
    async uri => {
        var httpClient = new HttpClient(); // HttpClient isn't thread-safe, so protect against concurrency by using a dedicated instance for each request.
        var result = await httpClient.GetAsync(uri);
        // do more stuff with result.
    },
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 20, CancellationToken = cancellationToken });
for (int i = 0; i < 1000; i++)
    block.Post(new Uri("http://www.server.com/req" + i));
block.Complete();
await block.Completion; // waits until everything is done or canceled.

As an alternative, you could use Task.Factory.StartNew passing in TaskCreationOptions.LongRunning so your task gets a new thread (not affiliated with threadpool) which would allow it to start immediately and call Cancel from there. But you should probably solve the threadpool exhaustion problem instead.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!