【问题标题】:BufferBlock getting blocked on OutputAvailableAsyncBufferBlock 在 OutputAvailableAsync 上被阻塞
【发布时间】:2019-12-10 20:09:56
【问题描述】:

我是使用 TPL 的新手。我已经能够在 BufferBlock 上实现一个简单的发布/接收事务,但是当我尝试异步时,我被挂了。

这是我正在尝试的简化版本。

声明消息缓冲区(使其成为全局)

Dim msgBuffer As New BufferBlock(Of String)

一个简单的发布消息的函数,它只是一个目录中的文件名列表

Private Sub PostMessagesToBuffer()

    filesList = Directory.GetFiles(txtBoxSrcFilesDir.Text, fileFilter).ToList
    For Each file In filesList
        msgBuffer.Post(file)
    Next
    msgBuffer.Complete()
End Sub

我创建了这个函数来处理消息:

Private Async Function ProcessMessagesAsync() As Task(Of Integer)

    Dim msgsProcessed = 0

    While Await msgBuffer.OutputAvailableAsync
        Dim msg = msgBuffer.Receive
        Console.WriteLine(msg)
        msgsProcessed += 1
    End While

    Return msgsProcessed

End Function

然后只需这组调用即可全部运行。

Dim msgProcessor = ProcessMessagesAsync()
PostMessagesToBuffer()
msgProcessor.Wait()
Console.writeLine("Processed " & msgProcessor.Result & " Messages.")

我可以调试并看到消息被添加到缓冲区中,但“等待时”从未收到消息在队列中可用的信号。它只是坐在那里,永远不会进入循环来处理消息。我在这里错过了一些相当简单的东西吗?

【问题讨论】:

  • 这是一个明显的死锁情况,代码无法通过 While 循环到达 PostMessagesToBuffer()。这通常发生在另一个线程上。
  • 这是什么应用程序?控制台应用程序? Windows 窗体?
  • 这是一个 Windows 窗体应用程序。
  • 这是有道理的。您的代码不应在控制台应用程序中死锁。但是 Windows 窗体应用程序在 UI 线程中安装了一个同步上下文,以强制异步工作流在 await 之后在 UI 线程中继续,这非常有用,但如果 UI 线程由于某种原因被阻塞,则会引入死锁的可能性.

标签: vb.net asynchronous async-await task-parallel-library tpl-dataflow


【解决方案1】:

您正在混合同步和异步代码。当blocking on async code 时,死锁很常见。而不是Wait:

msgProcessor.Wait()

...Await 更安全:

Await msgProcessor

DataflowBlock.Receive 也是一种阻塞方法。等待DataflowBlock.OutputAvailableAsync 后使用的正确方法是方法DataflowBlock.TryReceive。

我还应该注意,手动检索 DataflowBlock 的元素是可行的,但并不常见。通常数据流管道中的最后一个块是ActionBlock,它不会生成输出。

【讨论】:

  • 我会尝试一下,看看是否有帮助。我确实尝试切换到使用附加到处理方法的 ActionBlock。这似乎工作正常。
  • 你可以看看this的答案,我实现了一个与你的ProcessMessagesAsync非常相似的扩展方法ToListAsync,使用方法TryReceive而不是Receive。
猜你喜欢
  • 2014-10-09
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
相关资源
最近更新 更多