今天我决定试用多任务,看看与多线程相比,我是否获得了性能提升。我特别感兴趣,因为我正在寻找一种简单的方法来返回值并使用WaitAll或WaitAny等功能。我的问题是我做错了什么以及多任务实例的最佳方法是什么?
这是我使用Threads的旧代码。 (工作)
Thread[] threads = new Thread[5];
ScrapeFollowersIds[] scrapeClass = new ScrapeFollowersIds[5];
for (int i = 0; i < 5; i++)
{
scrapeClass[i] = new ScrapeFollowersIds();
threads[i] = new Thread(() => scrapeClass[i].ScrapeFollowers(cookie,proxy);
threads[i].Start();
}
这是我的新解决方案。
每个任务都显示我Status = Faulted,Method {null},Result尚未计算 查看异常我得到内部异常:索引超出了数组的范围
Task<string>[] scrapeFollowers = new Task<string>[5];
ScrapeFollowersIds[] scrapeClass = new ScrapeFollowersIds[5];
for (int i = 0; i < 5; i++)
{
scrapeClass[i] = new ScrapeFollowersIds();
scrapeFollowers[i] = Task<string>.Factory.StartNew(() =>
scrapeClass[i].ScrapeFollowers(cookie, proxy);
}
Im调用的方法看起来像这样
try
{
//Dosomething
return someString;
}
catch
{
return "";
}
答案 0 :(得分:3)
您正在关闭循环变量i
。
这两个程序实际上都存在这个错误。
由于定义要在另一个线程中运行的代码的lambda将关闭i
,并且i
最终会在代码实际运行之前被主线程(可能)更改。在循环内部获取循环变量的副本,然后关闭 。
话虽如此,您可以通过不创建所有任务需要手动访问的外部阵列来完全避免使用TPL的整个情况。这不是一种非常以TPL为导向的做事方式。而是让每个任务独立地创建其结果,然后聚合结果:
var tasks = Enumerable.Range(0, 5)
.Select(_ => Task.Run(() => CreateScrapeFollower(cookie, proxy)));
var results = Task.WhenAll(tasks);