【问题标题】:CoreMotion OperationQueue Issue on Apple WatchApple Watch 上的 CoreMotion OperationQueue 问题
【发布时间】:2018-03-08 19:41:16
【问题描述】:

设备:iPhone 8、Apple Watch Series 3

我目前正在开发一个手机应用程序 + 手表扩展程序,它使用标准 API 和相关的 OperationQueues 从所有 CoreMotion 传感器流式传输 CoreMotion 数据。

我需要能够并行流式传输所有 CoreMotion 传感器,将样本写入 csvs,然后将它们导出。将样本存储在数组中的内存会导致内存压力问题,因此现在我将每个样本直接写入文件,因为它是接收到的 - 所以对于 X=# 的流传感器,我也有 X 个文件被写入,也在关联的操作队列。

我的流式传输代码如下所示(例如,用于加速):

public func start(mm: CMMotionManager, fileQueue: OperationQueue, myOutputURL: URL) {
    if mm.isAccelerometerAvailable && !mm.isAccelerometerActive {
        mm.startAccelerometerUpdates(to: sampleQueue, withHandler: { (sample: CMLogItem?, error: Error?) in
        if let error = error as NSError? {
            print("There was a sampling error --- \(error.localizedDescription)")
        } else {
            if let accelerometerData = sample as? CMAccelerometerData {
                let now = Date().timeIntervalSince1970
                let sampleComponents: [Double] = [
                    now,
                    accelerometerData.timestamp,
                    accelerometerData.acceleration.x,
                    accelerometerData.acceleration.y,
                    accelerometerData.acceleration.z
                ]
                let row = sampleComponents.map({ String(format: "%.5f", $0) })
                let sampleString = row.joined(separator: ",") + "\n"
                if FileManager.default.fileExists(atPath: myOutputURL.path)
                    let writeOperation = BlockOperation(block: {
                        do {
                            if let utf8Sample = sampleString.data(using: .utf8) {
                                let fileHandle = try FileHandle(forWritingTo: myOutputURL)
                                fileHandle.seekToEndOfFile()
                                fileHandle.write(utf8Sample)
                                fileHandle.closeFile()
                            }
                        } catch let error as NSError {
                            print("There was an error while writing to file --- \(error.localizedDescription)")
                        }
                    })
                    if let lastOperation = fileQueue.operations.last {
                        writeOperation.addDependency(lastOperation)
                    }
                    fileQueue.addOperation(writeOperation)
                    print("Num OPs in Sample Queue: \(sampleQueue.operations.count)")
                    print("Num OPs in I/O Queue: \(fileQueue.operations.count)")
                }
            }
        })
    }
}

这很好用……在手机上。采样操作队列在任何给定时间很少有超过 100 个总操作,文件队列最多 5 个 - 即使流式传输超过一个小时。然而,我在我的 watchkit 扩展中使用完全相同的代码来传输加速度和运动数据,并且发生了一些特殊的事情。传感器数据的样本队列无限增加。换句话说,就好像来自 CoreMotion 采样的操作永远不会从采样队列中出列。

旁注:除了依赖链,队列还配置了:

    sampleQueue.maxConcurrentOperationCount = 1
    fileQueue.maxConcurrentOperationCount = 1

希望样品按顺序接收和编写。

这种无限增加导致在大约 15 分钟的流式传输后内存分配接近 80MB,我凭经验发现这是我的手表操作系统因压力过大而终止扩展时的近似上限。我已经记录了每个样本进入时样本队列中的操作数,当它接近 80MB 标记时,队列中大约有 60-80k 操作,而在 I/O 队列中,这个数字类似于那个电话。我不明白为什么,因为似乎更直观的是,磁盘 I/O 队列中存在瓶颈而不是样本队列中,尤其是随着文件大小和样本数量的增加。

我很好奇其他人是否遇到过这样的问题以及他们是如何克服的,因为这似乎是从 Apple 设备存储和导出传感器数据的一个相当标准的问题。

具体来说,我很好奇其他人如何设法在这些设备上长时间流式传输和存储传感器数据以供日后分析,如果您觉得我做的事情不正确。非常感谢!

【问题讨论】:

    标签: swift memory-management apple-watch nsoperationqueue core-motion


    【解决方案1】:

    我认为这样做的关键是在 Watch 本身上进行尽可能少的处理。

    这并不能直接解决问题,但我所做的是将数据从 Watch 流式传输到 iPhone,并在 iPhone 上完成对 CSV 的处理。这避免了让手表做任何繁重的工作(这对于旧手表来说更为重要)。

    另外,你的 updateInterval 是多少?

    【讨论】:

    • 当时我为每个传感器以 100Hz 的频率在所有气缸上点火。我也,最终做了类似于你提到的事情。我使用 applicationContext WatchConnectivity API 批量发送样本到手机,并将所有内容写入手机上。
    • 感谢您的跟进 - 您在 100Hz 采集时是否遇到过丢帧问题?我做了与你类似的事情,发现我的结果有时会丢失数据。我在这里解释一下:stackoverflow.com/questions/51254944/…你有我可以查看的代码仓库吗?
    猜你喜欢
    • 1970-01-01
    • 2015-06-30
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多