haskell - 管道.并发: Sent signal is delivered one click later than expected

标签 haskell concurrency gtk3 haskell-pipes

我正在使用 Pipes.Concurrent 和 GTK 编写一个简短的 GUI 程序。这是一款扫雷式游戏,因此我正在构建一个按钮网格。

我构建并连接我的按钮:

b <- buttonNewWithLabel (show $ adjacencies board ! i)
on b buttonActivated 
     $ void . atomically $ send output (ClickSignal i (mines board ! i))
return b

我将管道连接到:

(output, input)  <- spawn (latest (ClickSignal 0 False))

let run = do
        sig <- await
        case sig of
            ClickSignal i isMine ->
                if isMine
                then do
                    lift $ labelSetText info (show i ++ " -- LOSE!")
                else do 
                    lift $ labelSetText info (show i ++ " -- Ok")
                    run
            Empty -> do
                lift $ labelSetText info "Empty Case"
                run

void . forkIO $ do 
    runEffect $ fromInput input >-> run
    performGC

几乎按预期运行。但如果我点击按钮 1,什么也不会发生。但如果我按下按钮 23,它会将信息标签更新为“1..”。如果我单击另一个按钮,它将更新为“23..”,依此类推。

我怀疑要么是我无法理解并发管道在某种程度上是如何工作的,要么是惰性 IO 做了一些奇怪的事情。

最佳答案

使用latest缓冲策略意味着缓冲区中始终有一个值可供读取,因此 await总是会立即返回;和send只要有机会运行,同样总会成功。我编写的一个测试程序在 ghci 中工作正常,但编译时它永远不会让试图从控制台读取的线程运行,并且 send ;我刚刚收到源源不断的0直到我终止该程序。

您的消费者run其中没有任何会导致其暂停的内容,因此它可能同样会导致尝试 send 的线程挨饿。至output 。如果是这样的话,小threadDelay 100大约在每次调用 run 之前可能有帮助。

另一种可能性,也是一种更有效的可能性,是使用一个缓冲区来阻止 Consumer直到有消息需要采取行动。为了避免阻止事件回调,您可以使用 newest 1缓冲策略,这总是会成功 send如果已有值,则覆盖当前值。

如果这些都没有帮助,那么我怀疑您正在使用的 GUI 框架的检测方式还存在其他问题,但我对 Haskell 中的 GTK 绑定(bind)不是很熟悉,所以我不能对此有很大帮助。

关于haskell - 管道.并发: Sent signal is delivered one click later than expected,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35167939/

相关文章:

haskell - 了解 `conduit` 输出

c - 如何从一个按钮发送信号,而其他按钮的回调函数没有将信号返回到 GTK+ 中的 main()

python - 在Python中将自己的树列表与GTK TreeView/TreeModel同步

用于类型检查类似于 ML 的模式匹配的算法?

haskell - 指数函数的简单实现

haskell - 如何使类型成为 Eq 的实例

java - 线程限制

c# - ConcurrentDictionary - 损坏的字典或错误的代码?

java - CompletableFuture.thenAccept 中使用的垃圾回收对象的可用性

gtk - 如何使用 gtk 3.0 将 textview 设置为不可编辑?