简体   繁体   English

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

[英]C# Multi-threaded app - structure?

So, I'll make an application for checking links if they're accessible(live). 因此,如果链接可以访问(实时),我将创建一个检查链接的应用程序。 My question is how to make the threads "always busy". 我的问题是如何使线程“总是忙”。 What I mean: The app run 100 threads(created with FOR loop for example) with 100 different URLs. 我的意思是:该应用程序运行100个线程(例如使用FOR循环创建),具有100个不同的URL。 So when 1 of the threads finish it's job(check if URL is available) to get new URL and start again immediately. 因此,当其中一个线程完成它的工作(检查URL是否可用)以获取新URL并立即重新启动。 So the 100 threads will work non-stop till all URLs are checked. 所以100个线程将不停地工作,直到检查所有URL。

How can I accomplish that? 我怎么能做到这一点?

What you are looking for is called the Producer-Consumer Model . 您正在寻找的是生产者 - 消费者模型 You have a pool of resources, that contains the list of urls to check, one thread can fill that pool, and your conumer threads can pull from that pool, if you have .NET 4 Parallel.ForEach does most of the work for you. 您有一个资源池,其中包含要检查的URL列表,一个线程可以填充该池,并且您的conumer线程可以从该池中提取,如果您有.NET 4 Parallel.ForEach为您完成大部分工作。

Using 100 threads also is very likely not going to be the optimum number of threads, just let the Task Parallel Library manage the thread count for you. 使用100个线程也很可能不是最佳线程数,只需让Task Parallel Library为您管理线程数。

Here is a example if the list will be pre-populated and not have more items added as the thread is running. 下面是一个示例,如果列表将预先填充,并且在线程运行时没有添加更多项目。

//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.
}

If you need to populate the collection as it runs, replace List<string> with a concurrent collection like BlockingCollection 如果需要在运行时填充集合,请将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.
}

I also wanted to add that the automated thread scheduling may not be the best also, it may put some limits that could be expanded on, see this comment from the original question 我还想补充一点,自动线程调度可能也不是最好的,它可能会有一些可以扩展的限制,请参阅原始问题的评论

For those, who said/upvoted 100 thread is a terrible idea: On my dual core 2GB RAM XP machine Parallel.Foreach never created more than 5 threads(unless I set ThreadPool.SetMinThreads) and creating 100 threads resulted always ~30-40% faster operation. 对于那些说/ upvoted 100线程的人是一个可怕的想法:在我的双核2GB RAM XP机器上Parallel.Foreach从未创建超过5个线程(除非我设置ThreadPool.SetMinThreads)并创建100个线程总是~30-40%更快的操作。 So don't leave everything to Parallel.Foreach . 所以不要把所有东西留给Parallel.Foreach。 PS: My test code WebClient wc = new WebClient();var s = wc.DownloadString(url); PS:我的测试代码WebClient wc = new WebClient(); var s = wc.DownloadString(url); (google's home page) – LB (谷歌的主页) - LB

Use the Parallel CTP stuff, the parallel foreach method included will do exactly what you want. 使用并行CTP的东西,包含的并行foreach方法将完全符合您的要求。

Google is your friend. 谷歌是你的朋友。

Also, using 100 threads may not be best for performance, I would use however many cores are available. 此外,使用100个线程可能不是最佳性能,但我会使用许多内核。

You could use ThreadPool and give it the list of urls to process, then let a DoWork method handle the checking of whether they are live or not, eg 您可以使用ThreadPool并为其提供要处理的URL列表,然后让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
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM