奥尔良谷物任务调用结果
Result of task invocation on a grain in Orleans
对于这个长问题,我深表歉意。我一直在试验 Orleans 以了解它的各种属性,这些问题在逻辑上都在一个保护伞下。
第一个测试涉及每 1 秒从客户端向特定 grain 发出请求,而 grain 需要 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
由于 Orleans 中的 grains 是单线程的,因此仅调用第一个请求,其余请求在 grain 端排队。我对这部分的问题是:-
在普通 C# 中,当调用异步方法时,它会在主线程上继续,直到它在启动等待表达式作为另一个任务和 returns 该任务时遇到 await 语句。因此,调用者将被阻塞,直到 await 语句被命中。同样,这里客户端也应该被阻塞 10 秒,之后第一个请求 grain returns 任务。但是,这不会发生。客户端继续安排任务而不会被阻塞。
- 那么,客户端对grains的调用是
FireAndForget
?
- 如果是,那么他们如何取回任务对象?
- 当客户端调用 grain 对象并且运行时将 Task 对象返回给客户端时,是否涉及任何类型的阻塞?
第二个测试涉及从一个 grain 向另一个 grain 发出请求,其中第二个 grain 在返回之前等待 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
我在这里看到的情况与第一个实验中客户端发生的情况类似。所以,这些问题仍然存在。然而,这里发生了一件更奇怪的事情。 inner grain 的控制台输出无处出现。 为什么 inner grain 没有执行? 如果我在 outer-grain 代码中启用注释掉的行,并等待 inner grain 任务,将出现以下似乎有效的输出。
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
第一部分
不,调用 grain 时没有阻塞。 post 进一步清除了调用 grain 时发生的情况。
第二部分
虽然 grains 是单线程的是正确的,但假设每个 grain 在 Orleans 都有自己的线程是错误的。正如@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)
。第一个 grain 正在阻塞线程,使第二个 grain 没有机会执行。
感谢 Tseng 和 Reuben Bond 把事情说清楚。
对于这个长问题,我深表歉意。我一直在试验 Orleans 以了解它的各种属性,这些问题在逻辑上都在一个保护伞下。
第一个测试涉及每 1 秒从客户端向特定 grain 发出请求,而 grain 需要 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
由于 Orleans 中的 grains 是单线程的,因此仅调用第一个请求,其余请求在 grain 端排队。我对这部分的问题是:-
在普通 C# 中,当调用异步方法时,它会在主线程上继续,直到它在启动等待表达式作为另一个任务和 returns 该任务时遇到 await 语句。因此,调用者将被阻塞,直到 await 语句被命中。同样,这里客户端也应该被阻塞 10 秒,之后第一个请求 grain returns 任务。但是,这不会发生。客户端继续安排任务而不会被阻塞。
- 那么,客户端对grains的调用是
FireAndForget
? - 如果是,那么他们如何取回任务对象?
- 当客户端调用 grain 对象并且运行时将 Task 对象返回给客户端时,是否涉及任何类型的阻塞?
第二个测试涉及从一个 grain 向另一个 grain 发出请求,其中第二个 grain 在返回之前等待 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
我在这里看到的情况与第一个实验中客户端发生的情况类似。所以,这些问题仍然存在。然而,这里发生了一件更奇怪的事情。 inner grain 的控制台输出无处出现。 为什么 inner grain 没有执行? 如果我在 outer-grain 代码中启用注释掉的行,并等待 inner grain 任务,将出现以下似乎有效的输出。
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
第一部分
不,调用 grain 时没有阻塞。
第二部分
虽然 grains 是单线程的是正确的,但假设每个 grain 在 Orleans 都有自己的线程是错误的。正如@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)
。第一个 grain 正在阻塞线程,使第二个 grain 没有机会执行。
感谢 Tseng 和 Reuben Bond 把事情说清楚。