SignalR Core - 按顺序处理的请求

SignalR Core - requests handled sequentially

如果我通过到一个集线器的一个连接发出许多请求,它们将由服务器按顺序执行。所以没有parallism的进步

我的集线器中有三种不同的方法

    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);

我得到了以下输出

如果你看一下“Test2: Before Delay ... InvokeID: 2”将在“Test1: After Delay ... InvokeID: 1”之后直接被调用。似乎同时只允许一个 Hub 对象,无论所有三个调用都会立即 returns “RanToCompletion” 它们将一个接一个地执行。

它似乎非常具体,但我想构建一个应用程序,其中每个图形 WPF 对象都将调用 SignalR 来检索内容。如果他们将被顺序调用,我必须寻找其他解决方案。

我错过了什么?

您没有指定,但如果我不得不猜测,我会说您正在本地测试,这可能意味着您也在使用 IIS Express。 IIS Express 是单线程的,因此多个并发请求将总是排队,因为需要一个线程来处理每个请求。

至于为什么您的 RanToCompletion 日志排在第一位,您没有提供任何实际记录该日志的代码。结果,我又不得不在黑暗中刺一刀。在记录该消息之前,您很可能没有正确等待异步任务。任务本身将 运行 并在它们完成时完成,但调用代码继续并在此之前点击您的 RanToCompletion 日志行。

编辑

其实我现在明白了RanToCompletion的作用,一定是t.Status的值。你的异步方法中的代码 returns 立即,因为你没有在等待任何东西。包含的异步任务已启动,但在方法 returns 时尚未完成。然后,你的 ContinueWith lambda 是 运行,然后里面的任务完成并记录其他消息。

SignalR Core 中的设计将按顺序处理消息。

我搜索了来源 https://github.com/aspnet/SignalR。在 class

发表评论
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.

因此您必须创建额外的 class 来处理您的操作,并且您的 Hub 必须立即 return。但是不要忘记将 connectionId 传递给您的 class,这样您就可以使用 connectionId 进行回复,因为您的原始 Hub 已被破坏与此同时。