【问题标题】:SignalR Core - requests handled sequentiallySignalR Core - 按顺序处理的请求
【发布时间】:2018-08-29 14:13:49
【问题描述】:

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

我的中心有三种不同的方法

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

我得到了关注 OUTPUT

  • 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”之后直接调用。似乎同时只允许一个 Hub 对象,不管三个调用都会立即返回“RanToCompletion”,它们都会一个接一个地执行。

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

我错过了什么?

【问题讨论】:

  • 很简单,不要在你的hub方法中阻塞就可以了。

标签: asp.net-core-signalr


【解决方案1】:

将在 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.

因此,您必须创建额外的类来处理您的操作,并且您的 Hub 必须立即返回。但是不要忘记将 connectionId 传递给您的班级,以便您可以使用 connectionId 进行回复,因为您原来的 Hub 会同时被破坏。

【讨论】:

  • 对于任何正在阅读的人 - 如果曾经有过,可能不再是这种情况了 - 在 Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher 中再也找不到提到的评论。我在文档中也找不到任何关于此的具体内容。 Iirc,MS 表示我们不应该依赖执行顺序 - 在实际用例中使用顺序执行的这个 idea 之前,请先检查并尝试自己。
【解决方案2】:

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

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

编辑

实际上,我现在看到了RanToCompletion 的来源。它必须是t.Status 的值。您的异步方法中的代码会立即返回,因为您没有在等待内部的任何内容。包含的异步任务已启动,但在方法返回时尚未完成。然后,您的 ContinueWith lambda 运行,之后内部的任务完成并记录其他消息。

【讨论】:

  • 谢谢你,克里斯。是的 RanToCompletion 来自 t.Status。但这是我预期的行为。在客户端,我想发送“请求”并继续前进(例如 GUI)。但是在服务器上,请求将一个接一个地依次处理。如您所见,Test3 仅等待 Test1 的 1/4。但是在调试过程中,您会看到在 Test1 之后的 Test2 之后调用了 Test3。感谢您对 IIS Express 的提示。我今天将在单独的服务器上使用 IIS 进行检查。你知道我必须检查的特殊设置吗?
  • 没有。这只是单线程与多线程的简单问题。在完整的 IIS 上应该可以正常工作。
  • 克里斯,会按顺序处理。我在 SignalR Core 来源的评论中发现了这一点。您是否知道如何在此请求中编写此内容并将其标记为已解决?我要编辑原始请求还是添加新答案?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多