C#Locks - 在循环之前或内部锁定是否更好?

时间:2015-01-31 12:31:40

标签: .net loops thread-safety locks

我目前正在C#中创建一个Web Crawler,我有一个接收HTML字符串的方法,从中提取链接并将链接插入到捕获的所有链接的列表中。

由于它是多线程的,我使用了锁来防止同时从几个不同的线程访问所有字符串的列表。

使用锁更好?

此:

void ProcessHTML(string HTML)
{
    List<string> Links = GetLinks(HTML);
    for (int i = 0; i < Links.Count; i++)
    {
        lock (WebsitesHash)
        {
             lock (AllLinks)
             {
                  if (!WebsitesHash.ContainsKey(Links[i]))
                  {
                       WebsitesHash[Links[i]] = true;
                       AllLinks.Add(Links[i]);                    
                  }
             }
        }
    }
}

或者这个:

void ProcessHTML(string HTML)
{
    List<string> Links = GetLinks(HTML);
    lock (WebsitesHash)
    {
        lock (AllLinks)
        {
             for (int i = 0; i < Links.Count; i++)
             {
                  if (!WebsitesHash.ContainsKey(Links[i]))
                  {
                       WebsitesHash[Links[i]] = true;
                       AllLinks.Add(Links[i]);
                  }
             }
        }
    }
}

通常认为哪个更好 - 锁定每次迭代,或者锁定所有迭代?

其他可能相关的代码:

void StartCrawl(string Seed)
{
    AllLinks.Capacity = 1000 * 1000 * 10;
    StreamWriter Log = new StreamWriter(File.Open("Websites.txt", FileMode.Append));
    string HTML = GetHTML(Seed);
    ProcessHTML(HTML);
    for (int i = 0; i < AllLinks.Count; i++)
    {
        if (!Work)
        {
             Log.Close();
             WebsitesHash = new Dictionary<string, bool>();
             break;
        }
        Log.WriteLine(AllLinks[i]);
        websText.Text = AllLinks.Count + "";
        try { HTML = GetHTML(AllLinks[i]); }
        catch { continue; }
        Thread Parser = new Thread(() => ProcessHTML(HTML));
        Parser.Start();
    }
}

2 个答案:

答案 0 :(得分:2)

在这种情况下,它并不重要。

链接在锁外部进行了检索,因此唯一的操作是将少量字符串添加到列表中。这个很小,所以这个问题没有实际意义。

如果工作量较大,最好锁定环路内部。

虽然锁很便宜,但只需锁定一次即可优化一点。您可以使用private object lockObject = new object();更清楚地了解协议。

答案 1 :(得分:1)

让AllLinks成为链接的全局存储:

public List<string> AllLinks = new List<string>();

在代码中的某处使用List。BinarySearch方法添加新链接:

// "link" contain string of html link
lock(AllLinks)
{
    int index = AllLinks.BinarySearch(link);
    if( index < 0 )
    { // link is not in AllLinks
        AllLinks.Add(~index, link);
    }
    else
    { // link exist, "index" contain its position in list
        // ...
    }
}

我认为没有必要使用WebsitesHash对象。

UPD 使用BinarySearch的另一个好处是AllLinks的排序状态。