很长的问题我深表歉意。我一直在与奥尔良进行试验,以了解其各种特性,并且从逻辑上讲,这些问题都归根结底。
第一个测试涉及每1秒从客户端向特定的谷物发出一次请求,而谷物需要10秒才能执行请求。代码是这样的:
// client code
while (1)
{
Console.WriteLine("Client giving another request");
double temperature = random.NextDouble() * 40;
var sensor = client.GetGrain<ITemperatureSensorGrain>(500);
Task t = sensor.SubmitTemperatureAsync((float)temperature);
Console.WriteLine(t.Status);
Thread.Sleep(1000);
}
// grain code
public Task SubmitTemperatureAsync(float temperature)
{
long grainId = this.GetPrimaryKeyLong();
Console.WriteLine($"{grainId} outer received temperature: {temperature}");
Thread.Sleep(10000);
Console.WriteLine($"{grainId} outer complete");
return Task.CompletedTask;
}
控制台输出为:
Client giving another request
Task Status - WaitingForActivation
500 outer received temperature: 32.29987 <------------ print statement inside grain
Client giving another request <--------------------- client continues
Task Status - WaitingForActivation <------------------- client isn't blocked
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
Client giving another request
Task Status - WaitingForActivation
500 outer complete
由于奥尔良的谷物是单线程的,因此只有第一个请求被调用,其余的请求在谷物侧排队。我对此部分的问题是:-
在普通的C#中,当调用async方法时,它将在主线程上继续运行,直到在将其作为另一个Task启动等待的表达式并返回该Task时,它命中了await语句。因此,调用方被阻塞,直到命中await语句为止。同样,这里的客户端也应该被阻塞10秒钟,之后第一个谷物请求返回一个Task。但是,这不会发生。客户端将继续计划任务而不会被阻塞。
FireAndForget
的谷物调用是吗? 第二个测试涉及从一个谷物向另一个第二谷物等待10秒才返回的谷物发出请求。代码是这样的:
// client code
while (1)
{
Console.WriteLine("Client giving another request");
double temperature = random.NextDouble() * 40;
var sensor = client.GetGrain<ITemperatureSensorGrain>(500);
Task t = sensor.SubmitTemperatureAsync((float)temperature);
Console.WriteLine("Client Task Status - "+t.Status);
// make client sleep for a long time after the first request
// because we don't want any more requests from the client
Thread.Sleep(1000000000);
}
// outer-grain (ITemperatureSensorGrain) code
public async Task SubmitTemperatureAsync(float temperature)
{
long grainId = this.GetPrimaryKeyLong();
Console.WriteLine($"{grainId} outer received temperature: {temperature}");
while(true)
{
Console.WriteLine("Grain sending another request");
ITempBGrain sensor = this.GrainFactory.GetGrain<ITempBGrain>(400);
// await sensor.SubmitTempBAsync(temperature);
Task t = sensor.SubmitTempBAsync(temperature);
Console.WriteLine("Grain Task Status - "+t.Status);
Thread.Sleep(1000);
}
}
// inner-grain (ITempBGrain) code
public Task SubmitTempBAsync(float temperature)
{
long grainId = this.GetPrimaryKeyLong();
Console.WriteLine($"{grainId} internal received temperature: {temperature}");
Thread.Sleep(10000);
Console.WriteLine($"{grainId} internal complete");
return Task.CompletedTask;
}
控制台输出为:
Client giving another request
Client Task Status - WaitingForActivation
500 outer received temperature: 10.36764
Grain sending another request <-------------- Outer grain prints
Grain Task Status - WaitingForActivation
Grain sending another request <----------- Inner grain doesn't print
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
Grain sending another request
Grain Task Status - WaitingForActivation
warn: Orleans.Runtime.CallbackData[100157]
Response did not arrive on time in 00:00:30 for message: Request *cli/015ba7a5@d4cdc7ab->S127.0.0.1:30000:0*grn/6424EE47/000001f4 #17: . Target History is: <S127.0.0.1:30000:0:*grn/6424EE47/000001f4:>. About to break its promise.
Grain sending another request
Grain Task Status - WaitingForActivation
我在这里看到的内容与第一个实验中客户端发生的事情类似。因此,这些问题仍然存在。但是,这里发生了另一件事。内部谷物的控制台输出无处显示。 为什么内部谷物不执行?如果我在外部谷物代码中启用了注释行,并等待内部谷物任务,则会显示以下输出,该输出似乎有效。
Client giving another request
Client Task Status - WaitingForActivation
500 outer received temperature: 6.332514
Grain sending another request
400 internal received temperature: 6.332514
400 internal complete
Grain sending another request
400 internal received temperature: 6.332514
答案 0 :(得分:0)
第一部分
不,调用谷物时没有阻塞。 This帖子进一步明确了进行谷物呼叫时发生的情况。
第二部分
尽管谷物是单线程的是正确的,但假设每个谷物在奥尔良都有自己的线程是错误的。正如@Tseng所说的Orleans uses the async feature of .NET Core. It will process a grain until an async operation happens. Then it returns the thread to the thread-pool. This thread can be used by another grain to process data until the async operation is complete. When its complete, it resumes. its not necessary the same thread (but its the same context)
。第一个谷物阻塞了线程,第二个谷物没有机会执行。
感谢曾(Tseng)和鲁本·邦德(Reuben Bond)讲清楚的事情。