我有一个应用程序从Web获取大量信息并将其显示在带有WPF的窗口中。信息获取当然是在几个后台线程中完成的;他们中的大多数不应该是计算密集型(除了一些文本解析),但主要依赖于获取webcontent(webclient.Download ..和类似)。
由于我必须发送大量请求,因此我会启动很多线程,或者用户必须等待数小时才能完成所有内容的加载;由于这些线程中的许多线程主要是等待来自网络的数据和/或开始向网络服务发出新请求,因此理论上这不应该成为问题。然而,在实践中,调度程序的性能通常比没有运行的线程差。
后台线程由TPL数据流管道和Parallel.ForEach方法组合创建。我也已经尝试通过指定MaxThreads来限制线程数量,但由于任何数据流块都可以启动Parallel.Foreach块,我不认为这样做效果很好。
有没有办法增加调度员的优先级,性能或减少任何其他方式的口吃?
编辑:任务/线程的数量通常在50-100之间,在最坏的情况下可能多一点。 weblookup的典型场景是:向webservice发送请求,解析响应(< 10kb字符串)。对于每个响应,(parallel.foreach)下载此响应的数据,下载/缓存来自响应的任何图像并解析响应(例如,从维基百科文章中删除任何链接);等待他们全部完成并转到下一个查找。
答案 0 :(得分:1)
考虑使用WebClient.DownloadDataTaskAsync
等下载功能的异步版本,而不是启动新线程来下载数据。然后你不需要开始一个线程。只需致电
var result = await webClient.DownloadDataTaskAsync
并在await
之后处理结果。这基本上将启动下载操作并返回。下载完成后,将执行该方法的其余部分。最重要的是,它不会使用任何额外的线程。
答案 1 :(得分:1)
由于没有代码示例,并且根据帖子的语气,我认为您可以通过使用异步IO完全保存使用TPL Datablock
或Parallel.ForEach
提供的线程的用法基于模式。
如果您的主要目标是下载webcontent,我会尝试基于Task Asynchronous Pattern
的方法。例如,这是使用HttpClient
public async Task<string> DownloadWebContentAsync(string url)
{
var client = new HttpClient();
// Assuming a GET request
var response = await client.GetAsStringAsync(url);
// Do some string processing..
return response;
}
现在,消耗它:
await DownloadWebContentAsync(url);
答案 2 :(得分:0)
我不清楚你的后台线程不会像你说的那样造成很多CPU负载。即使平均而言它们负载很小,负载也可能会出现尖峰并导致口吃。
尝试将后台工作放在具有低优先级的TaskScheduler
上。 Parallel Extension Extras有TaskScheduler
支持。
您多久更新一次界面?也许它太频繁了。限制更新的频率。
我们还谈论了多少线程?如果数量达到数百个,请考虑使用异步IO。异步IO操作在运行时不使用线程。甚至不是后台主题。