查看Barrier
类,它允许n
线程在某个时间点集合。
static Barrier _barrier = new Barrier(3);
static void Main()
{
new Thread(Speak).Start();
new Thread(Speak).Start();
new Thread(Speak).Start();
}
static void Speak()
{
for (int i = 0; i < 5; i++)
{
Console.Write(i + " ");
_barrier.SignalAndWait();
}
}
//OUTPUT: 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4
但是
CountdownEvent
类也是如此:static CountdownEvent _countdown = new CountdownEvent(3);
static void Main()
{
new Thread(SaySomething).Start("I am thread 1");
new Thread(SaySomething).Start("I am thread 2");
new Thread(SaySomething).Start("I am thread 3");
_countdown.Wait(); // Blocks until Signal has been called 3 times
Console.WriteLine("All threads have finished speaking!");
}
static void SaySomething(object thing)
{
Thread.Sleep(1000);
Console.WriteLine(thing);
_countdown.Signal();
}
// output :
I am thread 3
I am thread 1
I am thread 2
All threads have finished speaking!
因此,似乎
Barrier
阻塞,直到n
线程开会为止而
CountdownEvent
也将阻塞,直到n
线程发出信号为止。从中学习有点使我困惑,我什么时候应该使用它。
问题:
在哪种情况下(实际情况),我应该选择使用
Barrier
而不是CountdownEvent
(反之亦然)? 最佳答案
关于这两者,有一些有趣的事情要注意:
CountdownEvent
没有与之关联的明确后置 Action 。 Barrier
可以。 CountdownEvent
和Barrier
大致相等,因此可以互换使用。 Barrier
可以具有多个阶段。每个阶段完成后,将执行后阶段操作;该操作完成后,下一阶段开始。 SO上有一个similar question讨论了此行为,但适用于C#类的Java等效项。答案给出了几个示例,这些示例对于C#等效项有效。
也就是说,请考虑一个现实世界的场景:检查3个信贷来源以寻找向购房者的潜在贷款。假设您在获得所有3个信用评分并对其进行评估之前,不想做出决定。您可以使用
CountdownEvent
(在Wait()
之后的代码检查分数)或在分数检查代码操作中使用单阶段障碍。在这里
Barrier
会是一个更好的选择:假设贷款员还希望检查购房者的SO信誉评分(因为专家用户获得了更好的信用!)和其他两个社交评分,但是仅在检索信用评分之后(因为嘿,如果不需要,我们不想检查社交媒体)。关于
Barrier
的一件整洁的事情是,您可以在单个方法调用中浏览各个阶段,从而使逻辑紧凑而整洁:var barrier = new Barrier(participantCount: 3, b => LogScoreAndPossiblyEvaluate(b));
var credit = new int[3];
var social = new int[3];
void LogScoreAndPossiblyEvaluate(Barrier b)
{
Log.Info("Got scores for {b.CurrentPhaseNumber == 1 ? "credit" : "social"} phase");
...
if (b.CurrentPhaseNumber == 2 && SomeComplexCalculationWithSixScores() == LoanResult.Approved)
LoanMoney();
}
...
for (int i=0; i<3; i++)
Task.Run(() => {
credit[i] = GetCreditScore(CreditSource(i);
barrier.SignalAndWait();
social[i] = GetSocialScore(SocialSource(i);
barrier.SignalAndWait();
// all phases done at this point
});