Проблема с CoreMotion OperationQueue на Apple Watch

Устройства: iPhone 8, Apple Watch Series 3

В настоящее время я работаю над приложением для телефона + расширением для часов, которое передает данные CoreMotion со всех датчиков CoreMotion с использованием стандартных API-интерфейсов в сочетании со связанными OperationQueues.

Мне нужно иметь возможность передавать все датчики CoreMotion параллельно, записывать образцы в csvs и затем экспортировать их. Хранение сэмплов в памяти в массиве вызвало проблемы с памятью, как и ожидалось, поэтому теперь я записываю каждый сэмпл непосредственно в файл по мере его поступления - поэтому для X=# потоковых датчиков у меня также есть X-файлы, которые записываются, также на связанные очереди операций.

Мой потоковый код выглядит следующим образом (например, для Accel):

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

В надежде, что образцы получены и написаны по порядку.

Это бесконечное увеличение приводит к тому, что выделение памяти приближается к 80 МБ после примерно 15 минут потоковой передачи, что я эмпирически обнаружил как приблизительную верхнюю границу, когда мои часы прекращают расширение из-за слишком большого давления. Я зарегистрировал количество операций в очереди образцов по мере поступления каждого образца, и к моменту, когда он приближается к отметке 80 МБ, в очереди около 60-80 000 операций, в то время как в очереди ввода-вывода число аналогично что по телефону. Я не могу понять почему, потому что кажется более интуитивным, что узкие места будут существовать в очереди дискового ввода-вывода, а не в очереди выборок, особенно с увеличением размеров файлов и номеров выборок.

Мне любопытно, сталкивались ли другие с такой проблемой или нет, и как они ее преодолели, потому что кажется, что это было бы довольно стандартной проблемой при хранении и экспорте данных датчиков с устройств Apple.

В частности, мне любопытно, как другим удалось передавать и хранить данные датчиков в течение длительных периодов времени на этих устройствах для последующего анализа, и если вы считаете, что что-то я делаю, неправильно. Большое спасибо!

1 ответ

Я думаю, что ключ к этому заключается в том, чтобы как можно меньше обрабатывать сами часы.

Это напрямую не решает проблему, но я сделал для потоковой передачи данных с часов на iPhone и обработки на CSV на iPhone. Это позволило избежать тяжелой работы часов (что тем более важно для старых часов).

Кроме того, каков ваш updateInterval?

Другие вопросы по тегам