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

use*_*644 5 c# multithreading structure

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

我怎么能做到这一点?

Sco*_*ain 10

您正在寻找的是生产者 - 消费者模型.您有一个资源池,其中包含要检查的URL列表,一个线程可以填充该池,并且您的conumer线程可以从该池中提取,如果您有.NET 4 Parallel.ForEach为您完成大部分工作.

使用100个线程也很可能不是最佳线程数,只需让Task Parallel Library为您管理线程数.

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

//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.
}
Run Code Online (Sandbox Code Playgroud)

如果需要在运行时填充集合,请替换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.
}
Run Code Online (Sandbox Code Playgroud)

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

对于那些说/ upvoted 100线程的人是一个可怕的想法:在我的双核2GB RAM XP机器上Parallel.Foreach从未创建超过5个线程(除非我设置ThreadPool.SetMinThreads)并创建100个线程总是~30-40%更快的操作.所以不要把所有东西留给Parallel.Foreach.PS:我的测试代码WebClient wc = new WebClient(); var s = wc.DownloadString(url); (谷歌的主页) - LB

  • @ user1410644你必须考虑瓶颈在哪里,如果你在100%cpu上投入更多线程就不会解决问题,如果在100个线程你仍然在空闲时因为所有队列都在网络服务器上等待你需要更多的线程.Parallel.Foreach为你管理这两种情况,它会根据需要生成尽可能多的线程,无论是2还是2000.唯一不会帮助你的地方就是你处于闲置状态,但你正在等待的东西已经饱和了请求更多的请求无济于事,从硬盘读取文件就是这个问题的一个很好的例子. (4认同)