NSStream (BLE L2CAP) 在后台线程上

问题描述 投票:0回答:1

我正在寻找对我正在做的事情的一些验证。此外,到处都有很多相关主题,但没有一个是完整的/解决所有挑战的。

概述/要求:

  • BLE (L2CAP) 中心能够与多个同时连接的外设进行通信
  • L2CAP 使用 NSStream
  • NSStream 应该在后台运行(以避免阻塞 UI/避免 UI 阻塞流)
  • NSStream 需要 RunLoop 因此它需要一个专用的非主线程

期望:

  • NSStreams 拥有所有系统资源,以便它们能够尽可能流畅地运行。

因此,经过大量研究和原型设计:

thread = Thread(block: { [weak self] in
        let runLoop = RunLoop.current
        let timer = Timer(timeInterval: 0.01, repeats: true, block: { [weak self] _ in self?.run() })
        
        inputStream.schedule(in: runLoop, forMode: .default)
        outputStream.schedule(in: runLoop, forMode: .default)

        CFRunLoopAddTimer(runLoop.getCFRunLoop(), timer, .defaultMode)
        CFRunLoopRun()
    })

然后退出:

    timer?.invalidate()
    CFRunLoopRemoveTimer(runLoop.getCFRunLoop(), timer, .defaultMode)
    CFRunLoopStop(runLoop.getCFRunLoop())
    thread?.cancel()

这有效 - 线程/RunLoop 运行/流接收事件,当需要停止时,RunLoop 结束/线程被取消。 我对 RunLoop 和自定义线程的担忧/问题:

  1. 我见过很多资料只是使用 RunLoop.main 来调度 NSStream。这似乎是不正确和不必要的。但我没有太多知识来支持它(无论我使用 main 还是background,它的工作原理都几乎相同,但我真的更喜欢使用background 来避免奇怪的间歇性行为)。

  2. 显然创建线程并不理想(因为我们有 GCD),但 NSStream API 需要它。我见过使用 DispatchQueue.global() 访问 CurrentRunLoop 的源代码,但显然 GCD 的工作线程数量有限,不建议这样做。

  3. 可以在同一个 RunLoop 中调度两个流吗?或者每个流一个线程更好?或者我可以在单个线程上调度 3 个外设(6 个流)吗?

  4. 计时器 - 对于计时器应该多久滴答一次有什么建议吗? BLE 通信 10 毫秒似乎不错,但真的是这样吗?据我所知,当我运行此代码时,CPU 使用率为 1%,所以这不是问题。但以 1 毫秒的速度运行会不会有点过分了? 有更好的方法(不使用计时器)吗?

  5. 我可以像这样生成多少个线程(在它们被重新使用之前)可能有一个硬性限制。我认为我不会拥有超过少数的连接外设(也受到 BLE 硬件的限制),但仍然如此。另一方面,在单元测试中,我可以通过这种方式(同时)生成 1000 个线程,并且代码在模拟器上运行良好。这正常吗?

multithreading core-bluetooth nsrunloop nsstream l2cap
1个回答
0
投票

这是一个相当广泛的问题,但根据我使用定制 BLE 硬件的经验,这里有一些答案:

我见过很多资料只是使用 RunLoop.main 来调度 NSStream。这似乎是不正确和不必要的。但我没有 有很多知识来支持它(无论我是否 使用主要或背景,但我真的更喜欢使用背景 避免奇怪的间歇性行为)。

我想这已经完成了,因为使用辅助

RunLoop
正确处理后台线程更加复杂。根据流上的负载,在主循环中处理事件通常是“可以的”——为了整体性能,当然最好在专用线程中执行此操作。

显然创建线程并不理想(因为我们有 GCD),但它是 NSStream API 需要。我见过使用的来源 DispatchQueue.global() 访问 CurrentRunLoop 但显然 GCD 有 工作线程数量有限,这种做法不是 推荐。

一些长时间运行的线程完全没有问题。

可以在同一个 RunLoop 中调度两个流吗? 或者每个流一个线程更好?或者我可以安排 3 个外围设备吗 (6x 流)在单个线程上?

这取决于您的延迟要求。我为每个专用外设使用一个线程,但将输入和输出流安排到该线程的 RunLoop。

计时器 - 对于计时器应该多久进行一次有什么建议吗? 打钩? BLE 通信 10 毫秒似乎不错,但真的是这样吗?据我所知 当我运行此代码时,看到 CPU 使用率为 1%,所以这不是问题。 但以 1 毫秒的速度运行会不会有点过分了?有更好的办法吗 (不使用定时器)?

我不确定你用计时器做什么。只需启动 RunLoop 并让流通过委托通知您即可。

我可以生成多少个线程,例如 这(在它们被重新使用之前)。我不认为我会拥有更多 少数连接的外设(也受到 BLE 硬件的限制),但是 仍然。另一方面,在单元测试中我可以在中生成 1000 个线程 这样(同时),代码在模拟器上运行良好。是 这正常吗?

这取决于您在这些线程中所做的事情,但总的来说:是的。桌面类系统可以毫无问题地处理许多线程。从一定数量开始,您会注意到性能受到影响,因为系统在调度上浪费了越来越多的时间。

© www.soinside.com 2019 - 2024. All rights reserved.