我正在尝试使用TPL块,并且遇到了令我困惑的地方。 TPL块应并行运行,具体取决于我的设置(MaxDegreeOfParallelism
)。
我做了什么?
我创建了5个块:
第1区块需要3秒钟才能完成
第2块需要1秒
......休息在几毫秒内完成
所有人都将MaxDegreeOfParallelism
设置为32(Environment.ProcessorCount
X 4),EnsureOrdered
设置为false
。一切都很好,每件事都是平行的。我假设这是我期望的最大吞吐量。我在我的块链中异步发送50条消息。一个简单的for循环递增整数值。
现在,我对Block 1进行了一次更改。我在ExecutionDataflowBlockOptions
TaskScheduler = new LimitedConcurrencyLevelTaskScheduler(2)
现在,此设置仅限我的Block 1为两个线程。只有并行运行时才能获得最多两个线程。这是代码:
class Example1
{
static void Main(string[] args)
{
Func<string, string> f = (string uri) =>
{
Thread.Sleep(3000);
Console.WriteLine(DateTime.Now.ToString() + $">>[{AppDomain.GetCurrentThreadId()}] block1...({uri})");
return uri.ToString(); ;
};
var block1 = new TransformBlock<string, string>(f, new ExecutionDataflowBlockOptions
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 32,
TaskScheduler = new LimitedConcurrencyLevelTaskScheduler(2)
});
var block2 = new TransformBlock<string, string[]>(text =>
{
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToString() + $">>[{AppDomain.GetCurrentThreadId()}] block2...({text})");
var retVal = new string[1];
retVal[0] = text;
return retVal;
}, new ExecutionDataflowBlockOptions
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 32,
});
var block3 = new TransformBlock<string[], string[]>(words =>
{
Console.WriteLine(DateTime.Now.ToString() + $">>[{AppDomain.GetCurrentThreadId()}] block3..({words[0]})");
return words;
}, new ExecutionDataflowBlockOptions
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 32
});
var block4 = new TransformManyBlock<string[], string>(words =>
{
Console.WriteLine(DateTime.Now.ToString() + $">>[{AppDomain.GetCurrentThreadId()}] block4...({words[0]})");
var retVal = new ConcurrentQueue<string>();
retVal.Enqueue(words[0]);
return retVal;
}, new ExecutionDataflowBlockOptions
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 32
});
var block5 = new ActionBlock<string>(reversedWord =>
{
Console.WriteLine(DateTime.Now.ToString() + $">>[{AppDomain.GetCurrentThreadId()}] block5...({reversedWord[0]})");
}, new ExecutionDataflowBlockOptions
{
EnsureOrdered = false,
MaxDegreeOfParallelism = 32
});
block1.LinkTo(block2);
block2.LinkTo(block3);
block3.LinkTo(block4);
block4.LinkTo(block5);
block1.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)block2).Fault(t.Exception);
else block2.Complete();
});
block2.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)block3).Fault(t.Exception);
else block3.Complete();
});
block3.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)block4).Fault(t.Exception);
else block4.Complete();
});
block4.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)block5).Fault(t.Exception);
else block5.Complete();
});
var d1 = DateTime.Now;
for (int i = 0; i < 50; i++)
{
block1.SendAsync(i.ToString());
}
block1.Complete();
block5.Completion.Wait();
var d2 = DateTime.Now;
Console.WriteLine($"Time taken {(d2.Ticks - d1.Ticks) / 10000000} seconds");
Console.WriteLine("DONE...");
Console.ReadLine();
}
当我考虑运行此代码时,
(t1,t2表示线程)
(B1(1)表示执行消息1的块1)
(B2(1)表示执行消息1的块2)
(B1(2)表示执行消息2的块1)
(T1,T2代表时间单位)
T1 T2
t1 B1(1) B1(3)...
t2 B1(2) B1(4)...
t3 B2(1)
t4 B2(2)
在时间段T2中,我的B2块将开始运行。但事实并非如此:
9/11/2017 4:48:55 PM>>[1240] block1...(1)
9/11/2017 4:48:55 PM>>[9688] block1...(0)
9/11/2017 4:48:58 PM>>[9688] block1...(3)
9/11/2017 4:48:58 PM>>[1240] block1...(2)
9/11/2017 4:49:01 PM>>[1240] block1...(5)
9/11/2017 4:49:01 PM>>[9688] block1...(4)
9/11/2017 4:49:04 PM>>[1240] block1...(6)
9/11/2017 4:49:04 PM>>[9688] block1...(7)
9/11/2017 4:49:07 PM>>[9688] block1...(9)
9/11/2017 4:49:07 PM>>[1240] block1...(8)
9/11/2017 4:49:10 PM>>[1240] block1...(11)
9/11/2017 4:49:10 PM>>[9688] block1...(10)
9/11/2017 4:49:13 PM>>[9688] block1...(13)
9/11/2017 4:49:13 PM>>[1240] block1...(12)
9/11/2017 4:49:16 PM>>[1240] block1...(15)
9/11/2017 4:49:16 PM>>[9688] block1...(14)
首先为所有消息运行Block 1,然后启动Block 2.
我在这里做错了吗?
或者我的期望是不正确的TPL块(管道和过滤器模式)?