我正在尝试创建一个TaskScheduler,以限制可以同时运行的线程数。我正在使用this example。问题是我看到了一些我不理解的行为。
如果我像示例一样创建类:
LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(5);
TaskFactory factory = new TaskFactory(lcts);
然后像这样运行它:
foreach (int i = 0; i < 10; ++i)
{
factory.StartNew(() => DoWork());
}
做工作看起来像这样:
private async Task DoWork()
{
// Do some stuff here like
StaticIntValueWorkOne++;
// And then more stuff that is async here
int someValue = await DoAdditionalWorkAsync();
Thread.Sleep(10000);
StaticIntValueWorkTwo++;
}
我看到的是
StaticIntValueWorkOne
立即增加10次,而StaticIntValueWorkTwo
仅增加一次。然后10秒钟后,我看到StaticIntValueWorkTwo
递增,然后每10秒钟递增一次。我没有得到的是DoAdditionalWorkAsync()
上的并发性。我以为我会看到StaticIntValueWorkOne
增加一次,然后StaticIntValueWorkTwo
增加一次。我想念什么?我只需要await
上的factor.StartNew()
吗? 最佳答案
我正在尝试创建一个TaskScheduler,以限制可以同时运行的线程数。
您可能要skip straight to the answer。 ;)
var scheduler = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 5)
.ConcurrentScheduler;
我没有得到的是DoAdditionalWorkAsync()上的并发性正在做什么。
任务计划程序仅适用于执行代码。当
async
方法在任务计划程序上执行时,您可以认为它被分解为多个任务,每个await
点都有一个中断。默认情况下,在await
之后,async
方法将重新输入其任务计划程序。 async
方法不在await
时在任务计划程序中。因此,在
await
ing方法期间,调度限制(一次5个)根本不适用。因此,在您的DoWork
中,该方法将首先递增变量,然后屈服于任务计划程序。产生收益时,它不会“计入”您的并发限制。稍后,当该方法恢复时,它将阻塞线程(执行“计数”)并增加第二个变量。使用此代码:
private static void Main(string[] args)
{
var scheduler = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 5)
.ConcurrentScheduler;
TaskFactory factory = new TaskFactory(scheduler);
for (int i = 0; i < 10; ++i)
{
factory.StartNew(() => DoWork());
}
Console.ReadKey();
}
private static int StaticIntValueWorkOne, StaticIntValueWorkTwo;
private static async Task DoWork()
{
// Do some stuff here like
Console.WriteLine(DateTime.UtcNow + " StaticIntValueWorkOne" + Interlocked.Increment(ref StaticIntValueWorkOne));
// And then more stuff that is async here
await Task.Yield();
Thread.Sleep(10000);
Console.WriteLine(DateTime.UtcNow + " StaticIntValueWorkTwo" + Interlocked.Increment(ref StaticIntValueWorkTwo));
}
我得到此(预期)输出:
3/20/2015 11:01:53 AM StaticIntValueWorkOne1
3/20/2015 11:01:53 AM StaticIntValueWorkOne5
3/20/2015 11:01:53 AM StaticIntValueWorkOne4
3/20/2015 11:01:53 AM StaticIntValueWorkOne2
3/20/2015 11:01:53 AM StaticIntValueWorkOne3
3/20/2015 11:01:53 AM StaticIntValueWorkOne6
3/20/2015 11:01:53 AM StaticIntValueWorkOne9
3/20/2015 11:01:53 AM StaticIntValueWorkOne10
3/20/2015 11:01:53 AM StaticIntValueWorkOne7
3/20/2015 11:01:53 AM StaticIntValueWorkOne8
3/20/2015 11:02:03 AM StaticIntValueWorkTwo1
3/20/2015 11:02:03 AM StaticIntValueWorkTwo3
3/20/2015 11:02:03 AM StaticIntValueWorkTwo2
3/20/2015 11:02:03 AM StaticIntValueWorkTwo4
3/20/2015 11:02:03 AM StaticIntValueWorkTwo5
3/20/2015 11:02:13 AM StaticIntValueWorkTwo6
3/20/2015 11:02:13 AM StaticIntValueWorkTwo7
3/20/2015 11:02:13 AM StaticIntValueWorkTwo8
3/20/2015 11:02:13 AM StaticIntValueWorkTwo9
3/20/2015 11:02:13 AM StaticIntValueWorkTwo10
如果要限制异步代码的并发性,请查看
SemaphoreSlim
或TPL Dataflow。关于c# - 等待和任务并发,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29159866/