C#多线程重复问题

3

我正在尝试制作一个工具,从我提供的多个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();

在使用较少的线程(10个线程 - 20个url)时,程序运行非常顺畅,但是在检查结果时发现有一些重复的结果和一些我提供的url丢失了。但是当使用20个线程处理20个url时就没有问题了。

请帮助我解决这个问题。谢谢。


闭包?尝试制作变量i的本地副本并在lambda内部使用它。 - Sebacote
1个回答

2
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为您管理线程的启动。


谢谢你提供的代码并解释,Rob。它对我很有用。非常感谢。 - SethSandaru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接