【问题标题】:Easy way to have X threads with ??? task?使用 ??? 拥有 X 线程的简单方法任务?
【发布时间】:2012-08-01 02:33:56
【问题描述】:

我有一个应用程序承担未知数量的任务。任务阻塞(他们在网络上等待)我需要多个线程来保持忙碌。

有没有一种简单的方法可以让我拥有一个庞大的任务和工作线程列表,它们会在空闲时拉出任务? ATM 我只是为每个任务启动一个新线程,这很好,但我想要一些控制,所以如果有 100 个任务,我就没有 100 个线程。

【问题讨论】:

  • 这通常被称为“线程池”,这种方法确实被 TPL(任务并行库)所采用。
  • 您使用的是哪个版本的 .NET? (.NET 4 的任务并行库使这变得更加容易。如果您可以在 .NET 4.5 中使用异步执行,它可能会更好......)
  • 你可以使用线程池,它会在需要时分配线程
  • @JonSkeet:我都可以使用。但在异步方面我更喜欢 4 ;)
  • 你看过这篇文章了吗? stackoverflow.com/questions/444627/…

标签: c# multithreading


【解决方案1】:

假设您正在处理的网络 I/O 类公开 Begin/End 样式的异步方法,那么您想要做的是使用 TPL TaskFactory.FromAsync 方法。正如TPL TaskFactory.FromAsync vs Tasks with blocking methods 中所述,FromAsync 方法将在后台使用异步 I/O,而不是让线程忙于等待 I/O 完成(这实际上不是您想要的)。

异步 ​​I/O 的工作方式是你有一个线程池可以在结果准备好时处理 I/O 的result,所以如果你有 100 个未完成的 I/操作系统你没有 100 个线程阻塞等待这些 I/O。当整个池都忙于处理 I/O 结果时,后续结果会自动排队,直到有线程空闲来处理它们。像这样让大量线程等待是可扩展性的灾难——线程是非常昂贵的对象,需要保持空闲状态。

【讨论】:

  • 我没用过,可以限制多少任务吗?我需要比这台机器上更多的内核数量来保持网络繁忙。我不能拥有 100 多个,因为我不希望网络太忙
  • TPL 自动选择“正确”的数字——您可以通过实现调度程序强制它指定一个数字,但我认为您会发现为您选择了最佳数字而无需额外工作.
  • 有关限制 TPL 中并行任务数量的更多信息,请参阅 stackoverflow.com/questions/5235710/…
【解决方案2】:

这里是一个通过线程池管理多个线程的 msdn 示例:

using System;

使用 System.Threading;

公共类斐波那契 { 公共斐波那契(int n,ManualResetEvent doneEvent) { _n = n; _doneEvent = 完成事件; }

// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
{
    int threadIndex = (int)threadContext;
    Console.WriteLine("thread {0} started...", threadIndex);
    _fibOfN = Calculate(_n);
    Console.WriteLine("thread {0} result calculated...", threadIndex);
    _doneEvent.Set();
}

// Recursive method that calculates the Nth Fibonacci number.
public int Calculate(int n)
{
    if (n <= 1)
    {
        return n;
    }

    return Calculate(n - 1) + Calculate(n - 2);
}

public int N { get { return _n; } }
private int _n;

public int FibOfN { get { return _fibOfN; } }
private int _fibOfN;

private ManualResetEvent _doneEvent;

}

公共类 ThreadPoolExample { 静态无效主要() { const int FibonacciCalculations = 10;

    // One event is used for each Fibonacci object
    ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
    Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
    Random r = new Random();

    // Configure and launch threads using ThreadPool:
    Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
    for (int i = 0; i < FibonacciCalculations; i++)
    {
        doneEvents[i] = new ManualResetEvent(false);
        Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
        fibArray[i] = f;
        ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
    }

    // Wait for all threads in pool to calculation...
    WaitHandle.WaitAll(doneEvents);
    Console.WriteLine("All calculations are complete.");

    // Display the results...
    for (int i= 0; i<FibonacciCalculations; i++)
    {
        Fibonacci f = fibArray[i];
        Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
    }
}

}

【讨论】:

  • 我在我的 cmets 中链接了那个 MSDN 示例。使用锁(ManualResetEvent)看起来很可疑,并且没有设置线程数量的示例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 2014-12-04
  • 2013-03-29
  • 1970-01-01
相关资源
最近更新 更多