SignalR Core - запросы обрабатываются последовательно - PullRequest
0 голосов
/ 29 августа 2018

Если я сгенерирую много запросов по одному соединению с одним концентратором, они будут последовательно выполняться сервером. Таким образом, парализм не продвигается вперед

У меня есть три разных метода в моем хабе

    public Task Test1(string invokeId)
    {
        Clients.Caller.SendAsync("Hello", $"Test1: Before Delay ... InvokeID: {invokeId}");
        Task.Delay(5000).Wait();
        Clients.Caller.SendAsync("Hello", $"Test1: After Delay ...  InvokeID: {invokeId}");
        return Task.CompletedTask;
    }

    public Task Test2(string invokeId)
    {
        Clients.Caller.SendAsync("Hello", $"Test2: Before Delay ... InvokeID: {invokeId}");
        Task.Delay(2500).Wait();
        Clients.Caller.SendAsync("Hello", $"Test2: After Delay ...  InvokeID: {invokeId}");
        return Task.CompletedTask;
    }

    public Task Test3(string invokeId)
    {
        Clients.Caller.SendAsync("Hello", $"Test3: Before Delay ... InvokeID: {invokeId}");
        Task.Delay(1250).Wait();
        Clients.Caller.SendAsync("Hello", $"Test3: After Delay ...  InvokeID: {invokeId}");
        return Task.CompletedTask;
    }

Я вызываю их из клиентского приложения .NET в цикле

_connection.SendAsync("Test1", "1").ContinueWith(t => Console.WriteLine($"Test1: { t.Status }"));
_connection.SendAsync("Test2", "2").ContinueWith(t => Console.WriteLine($"Test2: { t.Status }"));
_connection.SendAsync("Test3", "3").ContinueWith(t => Console.WriteLine($"Test3: { t.Status }"));

Метод следования за

_connection.On("Hello", new Type[] { typeof(string) }, (parameters, state) =>
{
    return Console.WriteLine((string)parameters[0]);
}, _connection);

Я получил следующий ВЫХОД

  • Test1: RanToCompletion
  • Test2: RanToCompletion
  • Test3: RanToCompletion
  • Test1: перед задержкой ... InvokeID: 1
  • Test1: после задержки ... InvokeID: 1
  • Test2: до задержки ... InvokeID: 2
  • Test2: после задержки ... InvokeID: 2
  • Test3: перед задержкой ... InvokeID: 3
  • Test3: после задержки ... InvokeID: 3

И если вы посмотрите, что «Test2: Before Delay ... InvokeID: 2» будет вызван непосредственно после «Test1: After Delay ... InvokeID: 1». Кажется, что только один объект-концентратор разрешен в одно и то же время, и независимо от того, что все три вызова немедленно возвращают «RanToCompletion», они будут выполняться один за другим.

Кажется, это очень специфично, но я хочу создать приложение, в котором каждый графический объект WPF будет вызывать SignalR для извлечения контента. Если они будут вызываться последовательно, я должен искать другое решение.

Что мне не хватает?

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Сообщение будет обрабатываться последовательно в рамках SignalR Core.

Я искал в источниках https://github.com/aspnet/SignalR. Комментарий в классе

Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher

функция

public override Task DispatchMessageAsync(HubConnectionContext connection, HubMessage hubMessage)
        // Messages are dispatched sequentially and will stop other messages from being processed until they complete.
        // Streaming methods will run sequentially until they start streaming, then they will fire-and-forget allowing other messages to run.

Таким образом, вы должны создать дополнительный класс, который будет обрабатывать ваши действия, и ваш концентратор должен немедленно вернуться. Но не забудьте передать connectionId вашему классу, чтобы вы могли использовать connectionId для ответов, потому что ваш первоначальный концентратор разрушен за это время.

0 голосов
/ 29 августа 2018

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

Что касается того, почему ваши RanToCompletion журналы идут первыми, вы не предоставили никакого кода, который фактически регистрирует это. В результате мне снова приходится наносить удар в темноте. Скорее всего, вы не ожидаете асинхронных задач должным образом до того, как это сообщение будет зарегистрировано. Сами задачи затем будут запускаться и завершаться всякий раз, когда они завершатся, но вызывающий код перемещается и попадает в вашу строку регистрации RanToCompletion до того, как это произойдет.

EDIT

На самом деле, теперь я вижу, куда входит RanToCompletion. Это должно быть значение t.Status. Код в ваших асинхронных методах возвращается немедленно, потому что вы ничего не ожидаете внутри. Содержащие асинхронные задачи запускаются, но еще не завершены к моменту возврата метода. Затем запускается ваша ContinueWith лямбда, после чего выполняемые задачи завершаются и регистрируются другие сообщения.

...