问题描述
我为这么长的问题道歉.我一直在尝试使用 Orleans 来了解它的各种特性,这些问题在逻辑上都归于一个保护伞之下.
I apologize for the long question. I have been experimenting with Orleans to know about its various properties and these questions are logically under one umbrella.
第一个测试涉及每 1 秒从客户端向特定谷子发出请求,而谷子需要 10 秒来执行请求.代码是这样的:
The first test involved making request from client to a specific grain every 1 second while the grain takes 10 seconds to execute the requests. The code is this:
// 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 中的谷物是单线程的,因此仅调用第一个请求,其余请求在谷物端排队.我对这部分的问题是:-
As grains in Orleans are single threaded, only first request is invoked and rest requests are queued on the grain side. My questions for this part are: -
在普通的 C# 中,当异步方法被调用时,它会继续在主线程上运行,直到它在将等待的表达式作为另一个任务启动并返回该任务时遇到 await 语句.因此,调用者被阻塞,直到命中 await 语句.类似地,客户端也应该被阻塞 10 秒,之后第一个对grain 的请求返回一个任务.然而,这不会发生.客户端继续调度任务而不会被阻止.
In normal C#, when an async method is called, it continues on the main thread till it hits the await statement when it starts the awaited expression as another Task and returns that Task. So, the caller is blocked till the await statement is hit. Similarly, here too the client should be blocked for 10s after which the first request to grain returns a Task. However, that doesn't happen. The client is continuing to schedule tasks without getting blocked.
- 那么,是来自客户端
FireAndForget
对谷物的调用吗? - 如果是,那么他们如何取回 Task 对象?
- 当客户端调用 Grain 对象并且运行时将 Task 对象带回客户端时,是否涉及任何类型的阻塞?
第二个测试涉及从一个grain向一个grain发出请求,其中第二个grain在返回之前等待10秒.代码是这样的:
The second test involved making request from a grain to a grain in which the second grain waits 10 seconds before returning. The code is this:
// 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
我在这里看到的情况与第一个实验中客户端发生的情况类似.所以,这些问题仍然存在.然而,这里发生了一件更奇怪的事情.内粒的控制台输出无处可见.为什么内粒不执行?如果我在外粒代码中启用注释掉的行,并等待内粒任务,则会出现以下似乎有效的输出.
What I see here is something similar to what happened with client in the first experiment. So, those questions are still there. However, here there is one more strange thing happening. The console output of inner grain appears nowhere. Why is the inner grain not executing? If I enable the commented out line in outer-grain code, and await the inner grain task, the following output appears which seems valid.
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 时没有阻塞.这篇帖子进一步阐明了当发出谷物调用.
First Part
No, there is no blocking when a call to a grain is made. This post further clears what happens when a grain call is made.
第二部分
虽然谷物是单线程是正确的,但假设每个谷物在奥尔良都有自己的线程是错误的.正如@Tseng 所说 Orleans 使用 .NET Core 的异步功能.它将处理一个grain,直到发生异步操作.然后它将线程返回到线程池.这个线程可以被另一个grain用来处理数据,直到异步操作完成.完成后,它会恢复.它不需要相同的线程(但它的上下文相同)
.第一个grain阻塞了线程,让第二个grain没有机会执行.
Second Part
While it is correct that grains are single threaded, it is wrong to assume that every grain has its own thread in Orleans. As @Tseng says 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)
. The first grain is blocking the thread giving no chance for the second grain to execute.
感谢 Tseng 和 Reuben Bond 把事情说清楚.
Thanks Tseng and Reuben Bond for making things clear.
这篇关于奥尔良谷物上的任务调用结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!