1

我有一个关于 Windows 和 Linux 上的线程(或纤程)的一般性问题,使用任何编程语言:

是否有可能让“第二个线程待命”并让它迅速投入行动并在几毫秒内帮助完成一项小任务,而不会被抢先?我应该补充一点,我希望没有互斥锁和自旋锁的清晰代码。

为了证明传统的线程池不适用于小型任务,请考虑 C# 中的矩阵求逆问题。我正在使用 Ivan Kuckir 的矩阵类。我复制他的 Invert 函数并将其称为 InvertParallel,如下所示:

public Matrix InvertParallel()   // modified from Ivan's Invert(), see link above
{
    if (L == null) MakeLU();
    Matrix inv = new Matrix(rows, cols);
    Parallel.ForEach<int>(Enumerable.Range(0, rows), rowID =>
    {
        Matrix Ei = Matrix.ZeroMatrix(rows, 1);
        Ei[rowID, 0] = 1;
        Matrix col = SolveWith(Ei);
        inv.SetCol(col, rowID);
    });
    return inv;
}

然后我调用 Invert 和 Invert_Parallel 函数并测量它所花费的时间:

static void Main()
{
    Stopwatch sw = new Stopwatch(); sw.Start();
    Matrix A = Matrix.IdentityMatrix(50, 50);
    Matrix I1 = A.Invert();
    long elapsed1 = sw.ElapsedMilliseconds;
    Matrix I2 = A.InvertParallel();
    long elapsed2 = sw.ElapsedMilliseconds - elapsed1;
    Console.WriteLine("Matrix size=" + A.rows + ", Invert=" + elapsed1 + "ms, Invert_Parallel=" + elapsed2 + "ms");
}

相当明显的结果表明,对于小型任务(矩阵大小 50),从线程池启动任务比运行单线程慢:

Matrix size=50,  Invert=  5ms,  InvertParallel=21ms
Matrix size=100, Invert= 19ms,  InvertParallel=24ms
Matrix size=200, Invert=137ms,  InvertParallel=44ms

(道歉 - 我必须从下面的注释中删除所有链接,因为我是新海报)

PS 可能相关的 S/O 文章:《如何同时启动两个线程》、《Linux - 线程和进程调度优先级》

PS 是的,我知道有一个更聪明的算法来计算逆,它的比例为 O(N^2.376)。

PPS 我不熟悉用户模式调度(Windows 上的 UMS)用户模式调度(Windows 上的“UMS”),有帮助吗?

4

1 回答 1

1

在线程之间传递任务,尤其是那些与它们相关联的大量数据的任务具有不小的开销,这可能会导致小型任务的性能变慢,如您所见。您需要找到使用多个内核更快的最佳位置。

顺便说一句,您可以通过创建一个工作线程来获得一个小的改进,当前线程保存一个上下文切换和缓存之间的副本。例如,如果您有 8 个内核,则将 1/7 传递给 7 个其他线程并在当前线程中执行 1/8。

于 2012-12-21T10:48:20.017 回答