更新:
我编写了一个异步 C 版本,它可以正常工作。
原来速度问题是由于 Python 的 GIL 造成的。有一种方法可以微调其行为。sys.setcheckinterval(间隔)
将间隔设置为零(默认为 100)可解决速度慢的问题。现在剩下的就是找出导致另一个问题的原因(并非所有像素都被填充)。这个没有任何意义。usbmon 显示所有通信都在进行。libusb 的调试消息没有显示任何异常。我想我需要获取 usbmon 的输出并比较同步与异步。usbmon 显示的数据乍一看似乎是正确的(第一个字节应该是 0x96 或 0x95)。
正如下面原始问题 S. Lott 中所说,它适用于 USB LCD 控制器。drv_send 有三个不同的版本,它是传出端点方法。我已经解释了下面的差异。如果我概述异步 USB 操作,也许会有所帮助。请注意,同步 USB 操作的工作方式相同,只是它是同步完成的。
我们可以将异步 I/O 视为 5 个步骤的过程:
- 分配:分配一个libusb_transfer(这是self.transfer)
- 填充:使用有关您希望执行的传输的信息填充 libusb_transfer 实例 (libusb_fill_bulk_transfer)
- 提交:要求 libusb 提交转账(libusb_submit_transfer)
- 完成处理:检查 libusb_transfer 结构中的传输结果(libusb_handle_events 和 libusb_handle_events_timeout)
- 释放:清理资源(下图未显示)
原始问题:
我有三个不同的版本。一个是完全同步的,一个是半异步的,最后一个是完全异步的。不同之处在于,同步完全填充了我正在控制的 LCD 显示器,并带有预期的像素,而且速度非常快。半异步版本只填充了一部分显示,但仍然非常快。异步版本真的很慢,只能填满一部分显示。我很困惑为什么像素没有完全填充,为什么异步版本真的很慢。有什么线索吗?
这是完全同步的版本:
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))
这是队列被清空的地方。这是 gobject 超时的回调。
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
这是转移的回调。它只是将锁定状态更改回 false,表示操作已完成。
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