7

我正在尝试加载一个间隔进程队列。换句话说,我有一个队列,我希望队列中的每个项目都以单独的间隔运行。

我的问题是我似乎一次无法运行超过 25 个线程。我在 64 位机器上使用 .Net 4.5,它的默认最大线程数为 32768。

如何让我的应用程序运行我的机器可以处理的尽可能多的并发线程?

这是一个示例应用程序,它在我的生产代码中复制了实际问题:

class Program
{
    static void Main(string[] args)
    {
        System.Threading.ThreadPool.SetMaxThreads(200, 200);
        test t = new test();

        t.LoadUrls("http://www.google.com");

        while (1 == 1)
        {
            System.Threading.Thread.Sleep(1000);//refresh every 5 seconds
            Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
        }
    }


    public class test
    {

        public void LoadUrls(string url)
        {
            for (int i = 0; i < 100; i++)
            {
                System.Threading.Timer t = new System.Threading.Timer(new System.Threading.TimerCallback(RunInterval), url, 0, 1000);
                Console.WriteLine("Loaded {0} feeds.", i);
            }
        }
        private static void RunInterval(object state)
        {
            string url = state as string;
            string data = "";

            using (System.Net.WebClient cl = new System.Net.WebClient())
            {
                Console.WriteLine("getting data for " + url);
                data = cl.DownloadString(url);
            }

            //do something with the data

        }
    }
}

这段代码理论上应该在 2 秒左右后运行 198 个线程。

顺便说一句,这在我的原型应用程序中运行良好;它是用节点写的。但是,现在我无法让它在 c# 中正常工作......

回答: 问题实际上是垃圾收集,根本不是线程池问题。池完全能够假脱我扔给它的所有线程。诀窍是使用 System.Threading.Timer 的单参数构造函数;这将使计时器将自身用作信号量,从而避免 gc。

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            test t = new test();
            t.url = "http://www.google.com?" + i;
            System.Threading.Timer ti = new System.Threading.Timer(new System.Threading.TimerCallback(t.RunInterval));
            ti.Change(0, 1000);
        }

        while (1 == 1)
            System.Threading.Thread.Sleep(int.MaxValue);
    }


    public class test
    {
        public string url { get; set; }
        public void RunInterval(object state)
        {
            Console.WriteLine("getting data for " + this.url);
            string data = "";

            using (System.Net.WebClient cl = new System.Net.WebClient())
            {
                data = cl.DownloadString(this.url);
            }
        }
    }
}

我不确定您为什么希望 gc 收集计时器,但是我知道什么。

4

3 回答 3

5

如何让我的应用程序运行我的机器可以处理的尽可能多的并发线程?

那是错误的做法。每个线程都是昂贵的,创建几百个,您的系统将严重退化。

您的代码使用 ThreadPool。池有一个算法来限制线程的数量。当您增加 Sleep() 时间时,您可能会看到更多线程。

更直接的方法是设置 ThreadPool.MinThreads。但期望更少的性能,而不是更多。

于 2013-01-10T19:08:29.487 回答
3

根据System.Threading.Timer

Use a TimerCallback delegate to specify the method you want the Timer to execute. The timer delegate is specified when the timer is constructed, and cannot be changed. The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.

然后在System.Threading.Threadpool

There is one thread pool per process. Beginning with the .NET Framework 4, the default size of the thread pool for a process depends on several factors, such as the size of the virtual address space. A process can call the GetMaxThreads method to determine the number of threads. The number of threads in the thread pool can be changed by using the SetMaxThreads method. Each thread uses the default stack size and runs at the default priority.

于 2013-01-10T19:15:47.527 回答
1

您想使用名为 MaxDegreeOfParallelism 的属性,但您需要稍微修改您的代码。然后对其进行测试并找出要并行运行的最佳线程数。这是链接:http: //msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.maxdegreeofparallelism.aspx

于 2013-01-10T19:12:04.077 回答