gpt4 book ai didi

c# - ContinueWith 不尊重奥尔良单线程性质

转载 作者:太空宇宙 更新时间:2023-11-03 19:40:18 30 4
gpt4 key购买 nike

我有以下代码(https://github.com/avinash0161/OrleansExperiments/tree/c0155b4b0c8c1bfe60aea8624f2cc83a52853dc7):

// Client code
Console.WriteLine("Client making a call");
var hashGenerator = client.GetGrain<IGrainA>(0);
hashGenerator.Call_A_ToTemp();
await Task.Delay(1000);
hashGenerator.Call_B_ToTemp();

// GrainA code
public async Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);

grain.CallA().ContinueWith((t)=>
{
if(t.IsFaulted)
{
// Silo message timeout is 32s so t.IsFaulted is true
Console.WriteLine("Task Faulted");
Call_A_ToTemp();
}
});
}

public async Task Call_B_ToTemp()
{
Console.WriteLine("Making call B to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);
await grain.CallB();
}

// GrainB code
public async Task CallA()
{
Console.WriteLine("Call A came to GrainB");
await Task.Delay(34000); // more than timeout for the caller
}

public Task CallB()
{
Console.WriteLine("Call B came to GrainB");
return Task.CompletedTask;
}

这段代码的输出是:

Client making a call
Making call A to a fellow grain
Call A came to GrainB
Making call B to a fellow grain
Task Faulted <---------------- This comes after Call_B_ToTemp executes
Making call A to a fellow grain

正如我们所见,Call_B_ToTemp 在 Call_A_ToTemp 完全执行之前执行(Call_A_ToTemp 的 ContinueWith 部分稍后执行)。这是预期的吗?它是否违反了 Cereal 的单线程性质?


当我将 Call_A_ToTemp() 中的代码替换为:

public async Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);

bool isSuccess = false;
while (! isSuccess)
{
try
{
await grain.CallA();
isSuccess = true;
} catch(TimeoutException){
Console.WriteLine("task faulted");
}

}
}

代码现在保留了单线程性质,并且在执行 Call_A_ToTemp() 的所有 ContinueWith 部分之前不会调用 Call_B_ToTemp。控制台输出如下:

Client making a call
Making call A to a fellow grain
Call A came to GrainB
Task Faulted
Making call A to a fellow grain

有人能解释一下吗?当存在ContinueWith时是否违反了单线程性质?

最佳答案

没有违反单线程的性质。您项目中的编译警告清楚地说明了问题的根源。特别是: 此异步方法缺少“await”运算符并将同步运行。考虑使用“await”运算符等待非阻塞 API 调用,或使用“await Task.Run(...)”在后台线程上执行 CPU 绑定(bind)工作。

async Task Call_A_ToTemp() 方法从不等待对 grain B 的调用。相反,它会在发出调用后立即返回。因为 Call_A_ToTemp() 返回的 Task 立即完成,所以允许在 grain 上执行另一个调用。一旦 grain.CallA() 完成,continuation (ContinueWith(...)) 将尽快在 grain 的 TaskScheduler 上执行(例如,当 Cereal 正在等待另一个电话或闲置时)。

相反,如果等待调用或者如果 async 从方法中删除并且代码更改为返回 grain.CallA().ContinueWith(...) 调用然后将观察到预期的行为。即,将代码更改为此将为您提供预期的结果:

// removed 'async' here, since we're not awaiting anything.
// using 'async' is preferred, but this is to demonstrate a point about
// using ContinueWith and un-awaited calls
public Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);

// Note the 'return' here
return grain.CallA().ContinueWith((t)=>
{
if(t.IsFaulted)
{
// Silo message timeout is 32s so t.IsFaulted is true
Console.WriteLine("Task Faulted");
Call_A_ToTemp();
}
});
}

关于c# - ContinueWith 不尊重奥尔良单线程性质,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54456369/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com