Проблема с 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?