Task.Factory.StartNew 的随机任务未启动

Random Tasks of Task.Factory.StartNew don't start

我需要并行完成 5 个任务,一次最多执行 2 个任务。 因此,一旦某个任务完成,下一个任务应该是 运行 - 直到没有待处理的任务。

我正在使用 solution by L.B.,其中涉及使用信号量进行跨任务同步。

void LaunchTaskPool ()
    {
        SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time.

        for (int i = 0; i < 5; i++)                     //loop through 5 tasks to be assigned
        {
            maxThreadSemaphore.Wait();                  //Wait for the queue

            Console.WriteLine("Assigning work {0} ", i);

            Task t = Task.Factory.StartNew(() =>
            {
                DoWork(i.ToString());                   // assign tasks
            }, TaskCreationOptions.LongRunning
                )
                .ContinueWith(
                (task) => maxThreadSemaphore.Release()  // step out of the queue
                );
        }

    }

    void DoWork(string workname)
    {
        Thread.Sleep(100);
        Console.WriteLine("--work {0} starts", workname);
        Thread.Sleep(1000);
        Console.WriteLine("--work  {0} finishes", workname);

    }

问题是一些随机任务甚至无法启动。例如这里的工作 1 和 3 从未开始,工作 4 得到了 运行 两次:

我尝试按照建议添加 Task.WaitAll() here,但没有帮助。

提前感谢您的建议!

康斯坦丁。

我建议改用 Parallel.For();无需重新发明轮子!使用Parallel.For()时可以指定MaxDegreeOfParallelism

例如:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp4
{
    class Program
    {
        static void Main()
        {
            Parallel.For(
                0, // Inclusive start
                5, // Exclusive end
                new ParallelOptions{MaxDegreeOfParallelism = 2},
                i => DoWork(i.ToString()));
        }

        static void DoWork(string workname)
        {
            Thread.Sleep(100);
            Console.WriteLine("--work {0} starts", workname);
            Thread.Sleep(1000);
            Console.WriteLine("--work  {0} finishes", workname);

        }
    }
}

(实际上我只是看了看,这已经在您链接的线程中的其他答案之一中 - 是否有您不想使用该解决方案的原因?如果不是,我想我们应该关闭它重复问题...)

无论如何回答你的实际问题:

You are accessing a "modified closure" in the loop. 要解决此问题,请在将循环变量 i 传递给任务之前复制它:

SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time.

for (int i = 0; i < 5; i++)                     //loop through 5 tasks to be assigned
{
    maxThreadSemaphore.Wait();                  //Wait for the queue

    Console.WriteLine("Assigning work {0} ", i);
    int copy = i; // <----- Make a copy here.

    Task t = Task.Factory.StartNew(() =>
            {
                DoWork(copy.ToString());                   // assign tasks
            }, TaskCreationOptions.LongRunning
        )
        .ContinueWith(
            (task) => maxThreadSemaphore.Release()  // step out of the queue
        );
}

您的解决方案的问题是,在 Task 开始之前,循环已经 运行 结束,并且正在开始下一个 Task

正如@Matthew Watson 所建议的那样,您应该使用 Parallel.For


出于兴趣,这将解决您的问题:

static void LaunchTaskPool()
{
    SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time.

    for (int i = 0; i < 5; i++)                     //loop through 5 tasks to be assigned
    {
        maxThreadSemaphore.Wait();                  //Wait for the queue

        Console.WriteLine("Assigning work {0} ", i);

        StartThead(i, maxThreadSemaphore);
    }
}

static void StartThead(int i, SemaphoreSlim maxThreadSemaphore)
{
    Task.Factory.StartNew(
        () => DoWork(i.ToString()),
        TaskCreationOptions.None
    ).ContinueWith((task) => maxThreadSemaphore.Release());
}

static void DoWork(string workname)
{
    Thread.Sleep(100);
    Console.WriteLine("--work {0} starts", workname);
    Thread.Sleep(1000);
    Console.WriteLine("--work  {0} finishes", workname);
}