【问题标题】:C# thread pool limiting threadsC#线程池限制线程
【发布时间】:2009-01-14 20:56:03
【问题描述】:

好的...我已经对该网站进行了公平的搜索,并阅读了许多有关此主题的帖子。我发现这个问题:Code for a simple thread pool in C# 特别有帮助。

但是,我的需求似乎总是有所不同。

我查看了 MSDN 示例并对其进行了一些调整以适应我的需要。我参考的例子在这里:http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80,printer).aspx

我的问题是这个。我有一组相当简单的代码,通过HttpWebRequestWebResponse 类加载网页并通过Stream 读取结果。我在一个线程中触发了这个方法,因为它需要执行很多次。该方法本身很短,但需要触发的次数(每次使用不同的数据)会有所不同。它可以是 1 到 200 之间的任何值。

我读过的所有内容似乎都表明ThreadPool 类是主要候选人。这就是事情变得棘手的地方。我可能需要启动这个东西说 100 次,但我最多只能运行 3 个线程(对于这个特定任务)。

我尝试通过以下方式在ThreadPool 上设置MaxThreads

ThreadPool.SetMaxThreads(3, 3);

我并不完全相信这种方法是有效的。此外,我不想破坏将在其上运行的系统上运行的其他网站或程序。那么,通过限制ThreadPool 上的线程数,我可以确定这仅与我的代码和我的线程有关吗?

MSDN 示例使用事件驱动方法并调用WaitHandle.WaitAll(doneEvents);,我就是这样做的。

所以我的问题的核心是,如何确保或指定可以为其代码运行的最大线程数,但让代码继续运行更多线程,因为之前的线程完成直到某个任意点?我是否以正确的方式解决这个问题?

此致,

杰森


好的,我添加了信号量方法并完全删除了ThreadPool 代码。看起来很简单。我的信息来自:http://www.albahari.com/threading/part2.aspx

正是这个例子向我展示了如何:

[下面的文字是从网站复制/粘贴]

容量为 1 的 Semaphore 类似于 Mutexlock,除了 Semaphore 没有“所有者”——它与线程无关。任何线程都可以在Semaphore 上调用Release,而对于Mutexlock,只有获得资源的线程才能释放它。

在以下示例中,十个线程执行一个循环,中间有一个 Sleep 语句。 Semaphore 确保不超过三个线程可以同时执行 Sleep 语句:

class SemaphoreTest
{
    static Semaphore s = new Semaphore(3, 3);  // Available=3; Capacity=3

    static void Main()
    {
        for (int i = 0; i < 10; i++)
            new Thread(Go).Start();
    }

    static void Go()
    {
        while (true)
        {
            s.WaitOne();

            Thread.Sleep(100);   // Only 3 threads can get here at once

            s.Release();
        }
    }
}

【问题讨论】:

    标签: c# multithreading c#-2.0 threadpool


    【解决方案1】:

    注意:如果您将其限制为“3”只是为了不让运行您的应用程序的机器不堪重负,我会首先确保这是一个问题。线程池应该为你管理这个。另一方面,如果您不想占用其他资源,请继续阅读!


    您无法管理线程池的大小(或其他任何事情)。

    在这种情况下,我会使用信号量来管理对资源的访问。在您的情况下,您的资源正在运行网络抓取,或计算一些报告等。

    为此,请在您的静态类中创建一个信号量对象:

    System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);
    

    然后,在每个线程中,您执行以下操作:

    System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);
    
    try
    {
        // wait your turn (decrement)
        S.WaitOne();
        // do your thing
    }
    
    finally {
        // release so others can go (increment)
        S.Release();
    }
    

    每个线程都会在 S.WaitOne() 上阻塞,直到收到继续执行的信号。一旦 S 被递减 3 次,所有线程都会阻塞,直到其中一个线程递增计数器。

    这个解决方案并不完美。


    如果您想要更简洁、更高效的东西,我建议您使用 BlockingQueue 方法,其中您将要执行的工作排入全局 Blocking Queue 对象。

    同时,您有三个线程(您创建的——不在线程池中),从队列中弹出要执行的工作。这并不难设置,而且非常快速和简单。

    例子:

    【讨论】:

    • Micheal,你能详细说明一下 Semaphore 的例子吗?这是我第一次阅读/听说它们。
    • Jason:我绝对推荐第二种方法(阻塞队列/生产者-消费者)——IMO 更容易。不过,有关信号量的更多信息,请阅读:msdn.microsoft.com/en-us/library/…
    • 不应该是Semaphore(3,3),WaitOne递减,Release递增吗?
    • @Bjarke Ebert:感谢您的更正:我已经更新了答案
    【解决方案2】:

    它和其他任何类一样是一个静态类,这意味着您对它所做的任何事情都会影响当前进程中的所有其他线程。它不会影响其他进程。

    不过,我认为这是 .NET 中较大的设计缺陷之一。谁想出了使线程池静态的绝妙主意?正如您的示例所示,我们通常需要一个专用于 我们的 任务的线程池,而不会干扰系统中其他地方的不相关任务。

    【讨论】:

    • 线程池用于进程范围。您正在寻找的是可以按需启用的任务管理器。如果您查看 Microsoft 的 ParallelLINQ 和 Task Parallel Library(将被整合到 .NET 4 中),它就会满足您的需求。
    • 这并不意味着它不是设计缺陷。他们应该从第一天起就允许它按需实例化。当然,如果他们想明确支持“进程范围”的任务,没有什么可以阻止他们也提供此类的静态实例。但我很高兴 .NET4 最终会修复它。
    • 当您意识到可用处理器/内核的数量也是相当静态时,这很有意义。无论如何,这些都是与所有其他进程、任务和线程共享的。那么,让一个应用程序中的两个线程池相互竞争同一组 CPU 资源有什么意义呢?
    • 控制。假设您有四个核心和两组任务,它们绝不能完全相互隔离。然后你可以创建两个线程池,每个线程池有三个线程。我的问题是为什么 允许它。明确阻止它有什么意义?
    • 如果您不想使用静态线程池,您可以轻松创建自己的自定义线程池。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    相关资源
    最近更新 更多