Обновление:
Я написал асинхронную версию C, и она работает как надо.
Оказывается, проблема скорости была из-за GIL Python. Есть способ точно настроить его поведение.
sys.setcheckinterval (интервал)
Установка интервала на ноль (по умолчанию 100) устраняет проблему медленной скорости. Теперь осталось выяснить, что является причиной другой проблемы (не все пиксели заполнены). Этот не имеет никакого смысла. usbmon показывает, что все коммуникации проходят. Отладочные сообщения libusb не показывают ничего необычного. Я думаю, мне нужно взять вывод usbmon и сравнить синхронизацию с асинхронным. Данные, которые показывает usbmon, на первый взгляд выглядят корректно (первый байт должен быть 0x96 или 0x95).
Как сказано ниже в исходном вопросе С. Лотта, это для USB LCD контроллера. Существует три разных версии drv_send, который является методом исходящей конечной точки. Я объяснил различия ниже. Может быть, это поможет, если я обрисую асинхронные операции USB. Обратите внимание, что синхронные операции USB работают одинаково, просто синхронно.
Мы можем рассматривать асинхронный ввод-вывод как 5-шаговый процесс:
- Распределение: выделить libusb_transfer (Это self.transfer)
- Заполнение: заполните экземпляр libusb_transfer информацией о переносе, который вы хотите выполнить (libusb_fill_bulk_transfer)
- Отправка: попросить libusb отправить передачу (libusb_submit_transfer)
- Обработка завершения: проверить результаты передачи в структуре libusb_transfer (libusb_handle_events и libusb_handle_events_timeout)
- Распределение ресурсов: очистить ресурсы (не показано ниже)
Оригинальный вопрос:
У меня есть три разные версии. Кто-то полностью синхронен, кто-то полуасинхронен, а последний полностью асинхронен. Разница в том, что синхронно полностью заполняет ЖК-дисплей, которым я управляю с ожидаемыми пикселями, , и это действительно быстро . Полусинхронная версия заполняет только часть экрана, , но все еще очень быстро . Асинхронная версия очень медленная, а заполняет только часть экрана. Я сбит с толку, почему пиксели заполнены не полностью, и почему асинхронная версия действительно медленная. Есть какие-нибудь подсказки?
Вот полностью синхронная версия:
def drv_send(self, data):
if not self.Connected():
return
self.drv_locked = True
buffer = ''
for c in data:
buffer = buffer + chr(c)
length = len(buffer)
out_buffer = cast(buffer, POINTER(c_ubyte))
libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0)
lib.libusb_submit_transfer(self.transfer)
while self.drv_locked:
r = lib.libusb_handle_events(None)
if r < 0:
if r == LIBUSB_ERROR_INTERRUPTED:
continue
lib.libusb_cancel_transfer(transfer)
while self.drv_locked:
if lib.libusb_handle_events(None) < 0:
break
self.count += 1
Вот полуасинхронная версия:
def drv_send(self, data):
if not self.Connected():
return
def f(d):
self.drv_locked = True
buffer = ''
for c in data:
buffer = buffer + chr(c)
length = len(buffer)
out_buffer = cast(buffer, POINTER(c_ubyte))
libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0)
lib.libusb_submit_transfer(self.transfer)
while self.drv_locked:
r = lib.libusb_handle_events(None)
if r < 0:
if r == LIBUSB_ERROR_INTERRUPTED:
continue
lib.libusb_cancel_transfer(transfer)
while self.drv_locked:
if lib.libusb_handle_events(None) < 0:
break
self.count += 1
self.command_queue.put(Command(f, data))
Вот полностью асинхронная версия. device_poll находится в потоке сам по себе.
def device_poll(self):
while self.Connected():
tv = TIMEVAL(1, 0)
r = lib.libusb_handle_events_timeout(None, byref(tv))
if r < 0:
break
def drv_send(self, data):
if not self.Connected():
return
def f(d):
self.drv_locked = True
buffer = ''
for c in data:
buffer = buffer + chr(c)
length = len(buffer)
out_buffer = cast(buffer, POINTER(c_ubyte))
libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0)
lib.libusb_submit_transfer(self.transfer)
self.count += 1
self.command_queue.put(Command(f, data))
И вот где очередь опустошается. Это обратный вызов для тайм-аута объекта.
def command_worker(self):
if self.drv_locked: # or time.time() - self.command_time < self.command_rate:
return True
try:
tmp = self.command_queue.get_nowait()
except Queue.Empty:
return True
tmp.func(*tmp.args)
self.command_time = time.time()
return True
Вот обратный вызов перевода. Он просто меняет заблокированное состояние обратно на ложное, указывая на то, что операция завершена.
def cb_send_transfer(self, transfer):
if transfer[0].status.value != LIBUSB_TRANSFER_COMPLETED:
error("%s: transfer status %d" % (self.name, transfer.status))
print "cb_send_transfer", self.count
self.drv_locked = False