Однопоточная нарезка зерен Орлеана

Я пытаюсь понять однопоточность зерен в Microsoft Orleans. Я использовал код из здесь и немного изменил его чтобы проверить мои сценарии.

Мой клиентский код и разрозненный код сборки

    static async Task Main(string[] args)
    {
        var siloBuilder = new SiloHostBuilder()
            .UseLocalhostClustering()
            .UseDashboard(options => { })
            .Configure<ClusterOptions>(options =>
            {
                options.ClusterId = "dev";
                options.ServiceId = "Orleans2GettingStarted";
            })
            .Configure<EndpointOptions>(options =>
                options.AdvertisedIPAddress = IPAddress.Loopback)
            .ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning).AddConsole());

        using (var host = siloBuilder.Build())
        {
            await host.StartAsync();

            var clientBuilder = new ClientBuilder()
                .UseLocalhostClustering()
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "dev";
                    options.ServiceId = "Orleans2GettingStarted";
                })
                .ConfigureLogging(logging => logging.AddConsole());

            using (var client = clientBuilder.Build())
            {
                await client.Connect();

                var random = new Random();
                string sky = "blue";

                while (sky == "blue") // if run in Ireland, it exits loop immediately
                {
                    Console.WriteLine("Client giving another request");
                    int grainId = random.Next(0, 500);
                    double temperature = random.NextDouble() * 40;
                    var sensor = client.GetGrain<ITemperatureSensorGrain>(grainId);

                    // Not awaiting this task so that next call to grain 
                    // can be made without waiting for current call to complete
                    Task t = sensor.SubmitTemperatureAsync((float)temperature);
                    Thread.Sleep(1000);
                }
            }
        }
    }

Мой интерфейс зернистости и фактическая реализация зернистости

public interface ITemperatureSensorGrain : IGrainWithIntegerKey
{
    Task SubmitTemperatureAsync(float temperature);
}


public class TemperatureSensorGrain : Grain, ITemperatureSensorGrain
{
    public async Task SubmitTemperatureAsync(float temperature)
    {
        long grainId = this.GetPrimaryKeyLong();
        Console.WriteLine($"{grainId} received temperature: {temperature}");

        await Task.Delay(10000);
        // Thread.Sleep(10000);
        Console.WriteLine($"{grainId} complete");
        // return Task.CompletedTask;
    }
}

В основном я отправляю запросы к зернам каждую секунду, тогда как я разрешаю каждому вызову метода внутри зерна занимать не менее 10 секунд. Теперь, согласно однопоточному выполнению гранул и расписанию времени выполнения Орлеана, описанному здесь, Я ожидаю, что запросы будут поставлены в очередь и следующий запрос не будет обработан зерном, если текущий метод запроса не завершится. Однако консоль вывод не подтверждает этого. Вывод консоли:

Client giving another request
344 received temperature: 8.162848
Client giving another request
357 received temperature: 10.32219
Client giving another request
26 received temperature: 1.166182
Client giving another request
149 received temperature: 37.74038
Client giving another request
60 received temperature: 26.72013
Client giving another request
218 received temperature: 24.19116
Client giving another request
269 received temperature: 17.1897
Client giving another request
318 received temperature: 8.562404
Client giving another request
372 received temperature: 8.865559
Client giving another request
443 received temperature: 5.254442
Client giving another request
344 complete        <-------------- The first request completed here
97 received temperature: 19.24687

Это дает понять, что следующий запрос обрабатывается зерном до завершения текущего запроса.

Вопросы:

  1. Итак, это нарушение однопоточной модели выполнения Орлеана или я что-то здесь упускаю?

  2. Кроме того, когда я использую Thread.sleep (10000) внутри зерна вместо Task.Delay (10000), я получаю тот же вывод консоли почти за исключением дополнительного предупреждения для каждого вызова запроса - Task [Id=1, Status=RanToCompletion] in WorkGroup [Activation: S127.0.0.1:11111:270246987*grn/6424EE47/00000028@cafcc6a5 #GrainType=Orleans2GettingStarted.TemperatureSensorGrain Placement=RandomPlacement State=Valid] took elapsed time 0:00:10.0019256 for execution, which is longer than 00:00:00.2000000. Означает ли это, что в идеале каждое зерно должно обрабатываться за 200 мс? Что будет, если зерна перевариться дольше?


person AvinashK    schedule 25.07.2018    source источник
comment
Они однопоточные для уникального идентификатора. TemperatureSensorGrain(grainId: 344) не будет выполнять несколько ходов параллельно, но TemperatureSensorGrain может выполнять множество разных идентификаторов параллельно.   -  person Dan Wilson    schedule 25.07.2018
comment
@DanWilson прав: каждое зерно эффективно однопоточное, но не весь бункер / кластер (поскольку это не будет масштабируемым).   -  person Reuben Bond    schedule 26.07.2018
comment
о ... Не знаю, как я это пропустил. Спасибо   -  person AvinashK    schedule 26.07.2018


Ответы (1)


Как говорит @DanWilson в комментариях, вы наблюдаете это поведение, потому что каждый вызов выполняется на отдельном зерне.

В Орлеане фактически однопоточным является каждое зерно, но не весь бункер или кластер. Это означает, что многие зерна могут выполняться одновременно, и это означает, что добавление большего количества ядер к вашему хосту или добавление большего количества машин позволит вам масштабировать вашу службу.

Изменив свой код, чтобы выбрать grainId только один раз (переместив его за пределы цикла), я вижу этот пример выполнения:

137 received temperature: 18.74616
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
137 complete
137 received temperature: 20.03226
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
Client giving another request
137 complete
137 received temperature: 21.4471

Как и следовало ожидать: многие запросы ставятся в очередь (по одному в секунду), но для завершения каждого запроса требуется 10 секунд, прежде чем зерно сможет начать обработку следующего запроса.

person Reuben Bond    schedule 25.07.2018