Task.Factory.StartNew的随机任务无法启动

Bus*_*ist 0 c# semaphore multitasking

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

我正在使用LB解决方案,解决方案涉及使用信号量来跨任务同步.

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);

    }
Run Code Online (Sandbox Code Playgroud)

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

产量

我尝试在这里建议添加Task.WaitAll(),但它没有帮助.

提前感谢您的建议!

康斯坦丁.

Mat*_*son 5

我推荐使用Parallel.For()这个; 没有必要重新发明轮子!您可以MaxDegreeOfParallelism在使用时指定Parallel.For():

例如:

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);

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(实际上我只是看了,这已经是你所链接的主题中的其他答案之一 - 你是否有理由不想使用该解决方案?如果没有,我想我们应该把这个问题作为重复来关闭. ..)

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

您正在循环中访问"修改后的闭包".要解决此问题,请在将循环变量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
        );
}
Run Code Online (Sandbox Code Playgroud)