C#多线程应用程序 - 结构?

时间:2012-07-20 15:20:15

标签: c# multithreading structure

因此,如果链接可以访问(实时),我会创建一个检查链接的应用程序。 我的问题是如何使线程“总是忙”。我的意思是说: 该应用程序运行100个线程(例如,使用FOR循环创建),具有100个不同的URL。因此,当其中一个线程完成它的工作(检查URL是否可用)以获取新URL并立即重新启动。因此,100个线程将不停地工作,直到检查完所有URL。

我该如何实现?

3 个答案:

答案 0 :(得分:10)

您正在寻找的是Producer-Consumer Model。你有一个资源池,其中包含要检查的url列表,一个线程可以填充该池,并且你的conumer线程可以从该池中提取,如果你有.NET 4 Parallel.ForEach完成大部分工作你。

使用100个线程也很可能不是最佳线程数,只需让任务并行库为您管理线程数。

这是一个示例,如果列表将预先填充,并且在线程运行时没有添加更多项目。

//Parallel.Foreach will block until it is done so you may want to run this function on a background worker.
public void StartThreads()
{
    List<string> myListOfUrls = GetUrls();

    Parallel.Foreach(myListOfUrls, ProcessUrl);
}


private void ProcessUrl(string url)
{
    //Do your work here, this code will be run from multiple threads.
}

如果您需要在集合运行时填充集合,请将List<string>替换为BlockingCollection等并发集合

BlockingCollection<string> myListOfUrls = new BlockingCollection();

//Parallel.Foreach will block until it is done so you may want to run this function on a background worker.
public void StartThreads()
{
    if(myListOfUrls.IsComplete == true)
    {
        //The collection has emptied itself and you told it you where done using it, you will either need to throw a exception or make a new collection.
        //use IsCompleatedAdding to check to see if you told it that you are done with it, but there still may be members left to process.
        throw new InvalidOperationException();
    }

    //We create a Partitioner to remove the buffering behavior of Parallel.ForEach, this gives better performance with a BlockingCollection.
    var partitioner = Partitioner.Create(myListOfUrls.GetConsumingEnumerable(), EnumerablePartitionerOptions.NoBuffering);
    Parallel.ForEach(partitioner, ProcessUrl);
}

public void StopThreads()
{
    myListOfUrls.CompletedAdding()
}

public void AddUrl(string url)
{
    myListOfUrls.Add(url);
}

private void ProcessUrl(string url)
{
    //Do your work here, this code will be run from multiple threads.
}

我还想补充一点,自动线程调度也可能不是最好的,它可能会有一些可以扩展的限制,请参阅原始问题的评论

  

对于那些说/赞成100线程的人是一个可怕的想法:在我的双重   核心2GB RAM XP机器Parallel.Foreach从未创建超过5个   线程(除非我设置ThreadPool.SetMinThreads)并创建100   线程结果总是使操作快30-40%。所以不要离开   一切都归功于Parallel.Foreach。 PS:我的测试代码WebClient wc = new   WebClient(); var s = wc.DownloadString(url); (谷歌的主页) - L.B

答案 1 :(得分:2)

使用并行CTP的东西,包含的并行foreach方法将完全符合您的要求。

Google是你的朋友。

此外,使用100个线程可能不是最佳性能,但我会使用许多内核。

答案 2 :(得分:0)

您可以使用ThreadPool并为其提供要处理的网址列表,然后让DoWork方法检查它们是否有效,例如。

 foreach (string s in URLs)
 {
       ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), s);
 }

 public void DoWork(object sender)
 {
       string url = (string)sender;
       //do stuff with url here
  }