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);
}
我需要并行完成 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);
}