Rya*_*yan 7 c# multithreading task-parallel-library parallel.foreach
所以情况就是这样:我需要拨打一个开始搜索的网站.这种搜索会持续一段时间,我知道搜索完成的唯一方法是定期查询网站,查看网站上是否有"下载数据"链接(它在javascript上使用了一些奇怪的ajax调用)用于检查后端和更新页面的计时器,我认为).
所以这就是诀窍:我需要搜索数百个项目,一次一个.所以我有一些看起来有点像这样的代码:
var items = getItems();
Parallel.ForEach(items, item =>
{
startSearch(item);
var finished = isSearchFinished(item);
while(finished == false)
{
finished = isSearchFinished(item); //<--- How do I delay this action 30 Secs?
}
downloadData(item);
}
Run Code Online (Sandbox Code Playgroud)
现在,显然这不是真正的代码,因为可能存在导致isSearchFinished永远存在的事物false.
除了显而易见的无限循环危险之外,我将如何正确地isSearchFinished()避免一遍又一遍地调用,而是每次拨打30秒或1分钟?
我知道Thread.Sleep()这不是正确的解决方案,我认为解决方案可能是通过使用来完成的,Threading.Timer()但我对它并不是很熟悉,并且有太多的线程选项,我只是不确定使用哪个.
使用任务很容易实现async/await,正如@KevinS在评论中所指出的那样:
async Task<ItemData> 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);
Run Code Online (Sandbox Code Playgroud)
这样,您就不会ThreadPool因为大多数I/O绑定的网络操作而无法阻塞线程.如果您不熟悉async/await,async-await标签维基可能是一个很好的起点.
我想你可以把你的同步方法isSearchFinished,并downloadData使用类似的异步版本HttpClient非阻塞HTTP请求,并返回Task<>.如果你不能这样做,你仍然可以简单地用Task.Run,包装,await Task.Run(() => isSearchFinished(item))和await Task.Run(() => downloadData(item)).通常不建议这样做,但是因为你有数百个项目,所以它会提供比Parallel.ForEach这种情况更好的并发性,因为你不会阻塞30秒的池线程,这要归功于异步Task.Delay.