我正在尝试制作一个工具,从我提供的许多URL获取源字符串。这段代码用于多线程
new Thread(() =>
{
while (stop != true)
{
if (nowworker >= threads)
{
Thread.Sleep(50);
}
else
{
if (i <= urllist.Count - 1)
{
var thread = new Thread(() =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
else
{
stop = true;
}
}
}
}).Start();
它的运行非常顺利,直到我检查结果,有一些重复的结果和缺少一些url我提供的,如果使用更少的线程为许多url(10线程- 20 url),但没有问题,当使用20线程为20 url。
请帮帮我。谢谢你。
if (i <= urllist.Count - 1)
{
var thread = new Thread(() =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
传递给线程的方法不能保证在i
(i++
)更新之前执行。事实上,它不太可能。这意味着多个线程可以使用相同的i
值,而i
的某些值不会有任何线程执行。
更糟糕的是,GetSource
可能使用与SaveToFile
不同的i
值。
在这里阅读:http://jonskeet.uk/csharp/csharp2/delegates.html
这将修复它:
if (i <= urllist.Count - 1)
{
var currentIndex = i;
var thread = new Thread(() =>
{
string source = GetSource(urllist[currentIndex]);
SaveToFile(source, currentIndex + ".txt");
});
thread.Start();
i++;
nowworker += 1;
}
更好的是,你可以这样替换整个代码块:
Parallel.For(0, urlList.Count - 1,
new ParallelOptions { MaxDegreeOfParallelism = threads },
i =>
{
string source = GetSource(urllist[i]);
SaveToFile(source, i + ".txt");
}
);
这将摆脱代码难闻的Thread.Sleep()
,并让。net为您管理旋转线程