Parallel.ForEach using Thread.Sleep equivalent

后端 未结 2 633
孤独总比滥情好
孤独总比滥情好 2021-01-18 07:40

So here\'s the situation: I need to make a call to a web site that starts a search. This search continues for an unknown amount of time, and the only way I know if the searc

2条回答
  •  耶瑟儿~
    2021-01-18 08:06

    It's quite easy to implement with tasks and async/await, as noted by @KevinS in the comments:

    async Task ProcessItemAsync(Item item)
    {
        while (true)
        {
            if (await isSearchFinishedAsync(item))
                break;
            await Task.Delay(30 * 1000);
        }
        return await downloadDataAsync(item);
    }
    
    // ...
    
    var items = getItems();
    var tasks = items.Select(i => ProcessItemAsync(i)).ToArray();
    await Task.WhenAll(tasks);
    var data = tasks.Select(t = > t.Result);
    

    This way, you don't block ThreadPool threads in vain for what is mostly a bunch of I/O-bound network operations. If you're not familiar with async/await, the async-await tag wiki might be a good place to start.

    I assume you can convert your synchronous methods isSearchFinished and downloadData to asynchronous versions using something like HttpClient for non-blocking HTTP request and returning a Task<>. If you are unable to do so, you still can simply wrap them with Task.Run, as await Task.Run(() => isSearchFinished(item)) and await Task.Run(() => downloadData(item)). Normally this is not recommended, but as you have hundreds of items, it sill would give you a much better level of concurrency than with Parallel.ForEach in this case, because you won't be blocking pool threads for 30s, thanks to asynchronous Task.Delay.

提交回复
热议问题