【问题标题】:Using a Swift Timer in a MacOS command-line-tool / daemon which uses Swift-NIO for networking: RunLoop vs wait issue在使用 Swift-NIO 进行网络的 MacOS 命令行工具/守护进程中使用 Swift 计时器:RunLoop 与等待问题
【发布时间】:2020-10-29 10:19:06
【问题描述】:

我正在转换 Swift MacOS 命令行工具/守护程序以使用 Swift-NIO 进行网络连接。这是我的第一个 Swift-NIO 项目。

该工具每 0.1 秒触发一次计时器。这是在 Swift-NIO 转换之前启动守护程序/运行循环的 main.swift 底部的行:

RunLoop.current.run()

这是我的 Universe.swift 类 init() 中的计时器。这个类总是只有一个实例:

    timer = Timer(timeInterval: 1.0 / updatesPerSecond, target: self, selector: #selector(timerFired), userInfo: nil, repeats: true)
    timer?.tolerance = 0.3 / updatesPerSecond
    debugPrint("Timer initialized")
    if let timer = timer {
        RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
    }

在此配置中,计时器按预期每秒触发 10 次。但是,如果我收到任何网络输入,我的 Swift-NIO 库就会崩溃,因为它不在预期的事件循环中。

在 Swift-NIO 中,我应该在 main.swift 的底部添加一个 channel.closeFuture.wait() 行:

// This will never unblock as we don't close the ServerChannel.
try channel.closeFuture.wait()
RunLoop.current.run()

这解决了 Swift-NIO 崩溃,但是我从来没有到达我的计时器 RunLoop,所以我的计时器没有触发。

如何使用 Swift-NIO 接收(和发送)网络数据,同时仍然有一个计时器运行?

如果有帮助,此项目的完整开源代码位于 https://github.com/darrellroot/netrek-server-swift

【问题讨论】:

  • 您看到的 SwiftNIO 崩溃缺少一些上下文。您能否提供您用于响应计时器触发的代码(timerFired 选择器)?这可能违反了线程要求。

标签: swift macos swift-nio


【解决方案1】:

卢卡萨是对的。我错过了(并且不理解)一些重要的上下文。

我的计时器最终尝试使用 SwiftNIO 发送数据,如下所示:

    if let context = context {
        let buffer = context.channel.allocator.buffer(bytes: data)
        _ = context.channel.writeAndFlush(buffer)
    }

解决方法是将流量“分派”到与上下文相关的 EventLoop:

    if let context = context {
        context.eventLoop.execute {
                let buffer = context.channel.allocator.buffer(bytes: data)
                _ = context.channel.writeAndFlush(buffer)
        }
    }

感觉非常类似于 DispatchQueue.main.async { } 用于更新 iOS 应用程序中的 GUI,但使用不同的 Swift-NIO 相关术语。

【讨论】:

    猜你喜欢
    • 2019-03-18
    • 2015-10-06
    • 2015-03-04
    • 2021-01-12
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多