带有串行设备的 asyncio python 占用 100% CPU
asyncio python with serial device takes 100% CPU
当我 运行 这个来自 rfxcom python library 的小主 :
from asyncio import get_event_loop
from rfxcom.transport import AsyncioTransport
dev_name = '/dev/serial/by-id/usb-RFXCOM_RFXtrx433_A1XZI13O-if00-port0'
loop = get_event_loop()
def handler(packet):
print(packet.data)
try:
rfxcom = AsyncioTransport(dev_name, loop, callback=handler)
loop.run_forever()
finally:
loop.close()
我看到 CPU 使用率越来越高(大约 100%)。
我不明白为什么:模块收到的消息很少(每 5 秒约 1 条消息),我认为当 epoll_wait 被调用时 CPU 应该空闲,等待下一个活动。
我用 python cProfile 启动了主程序,它显示了这个:
In [4]: s.sort_stats('time', 'module').print_stats(50)
Mon Jul 20 22:20:55 2015 rfxcom_profile.log
263629453 function calls (263628703 primitive calls) in 145.437 seconds
Ordered by: internal time, file name
List reduced from 857 to 50 due to restriction <50>
ncalls tottime percall cumtime percall filename:lineno(function)
13178675 37.280 0.000 141.337 0.000 /usr/local/lib/python3.4/asyncio/base_events.py:1076(_run_once)
13178675 31.114 0.000 53.230 0.000 /usr/local/lib/python3.4/selectors.py:415(select)
13178674 15.115 0.000 32.253 0.000 /usr/local/lib/python3.4/asyncio/selector_events.py:479(_process_events)
13178675 12.582 0.000 12.582 0.000 {method 'poll' of 'select.epoll' objects}
13178699 11.462 0.000 17.138 0.000 /usr/local/lib/python3.4/asyncio/base_events.py:1058(_add_callback)
13178732 6.397 0.000 11.397 0.000 /usr/local/lib/python3.4/asyncio/events.py:118(_run)
26359349 4.872 0.000 4.872 0.000 {built-in method isinstance}
1 4.029 4.029 145.365 145.365 /usr/local/lib/python3.4/asyncio/base_events.py:267(run_forever)
13178669 4.010 0.000 4.913 0.000 /home/bruno/src/DomoPyc/venv/lib/python3.4/site-packages/rfxcom-0.3.0-py3.4.egg/rfxcom/transport/asyncio.py:85(_writer)
因此,就运行时间而言,前三个函数调用是 python3.4/asyncio/base_events.py
、python3.4/selectors.py
和 python3.4/asyncio/selector_events.py
。
EDIT :类似 运行 的时间命令给出:
time python -m cProfile -o rfxcom_profile.log rfxcom_profile.py
real 2m24.548s
user 2m19.892s
sys 0m4.113s
谁能解释一下为什么?
EDIT2: 由于fonctions调用的次数非常多,我跟踪了一下流程,发现有epoll_wait 上的循环,超时值为 2 毫秒:
// many lines like this :
epoll_wait(4, {{EPOLLOUT, {u32=7, u64=537553536922157063}}}, 2, -1) = 1
我在base_event._run_once看到有计算超时时间,但我想不通。我不知道如何将此超时设置得更高以降低 CPU.
如果有人知道...
感谢您的回答。
我回答我的问题,因为它可能对其他人有用。
将环境变量 PYTHONASYNCIODEBUG
设置为 1 后,出现了如下几行:
DEBUG:asyncio:poll took 0.006 ms: 1 events
在 Rfxcom 库中,有一个带有队列的编写器机制,用于将数据推送到串行设备。意图是我认为 "asyncio, tell me when I can write, and then I'll flush the write queue"。所以有这样一行:
self.loop.call_soon(self.loop.add_writer, self.dev.fd, self._writer)
self.dev
是 Serial
class 实例,self.dev.fd
是串行文件描述符。
如the doc says"add_writer(fd, callback, *args) : Start watching the file descriptor for write availability"。
我认为串口设备总是可以写的所以我做了一个小脚本:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
loop = get_event_loop()
def writer_cb():
logger.info("writer cb called")
s = Serial('/dev/serial/by-id/usb-RFXCOM_RFXtrx433_A1XZI13O-if00-port0', 38400, timeout=1)
loop.add_writer(s.fd, writer_cb)
loop.run_forever()
并看到无限循环的行,使 CPU 达到 100%:
DEBUG:asyncio:poll took 0.006 ms: 1 events
INFO:root:writer cb called
所以我觉得没必要写writer callback,直接在串口设备上调用write
即可
当我 运行 这个来自 rfxcom python library 的小主 :
from asyncio import get_event_loop
from rfxcom.transport import AsyncioTransport
dev_name = '/dev/serial/by-id/usb-RFXCOM_RFXtrx433_A1XZI13O-if00-port0'
loop = get_event_loop()
def handler(packet):
print(packet.data)
try:
rfxcom = AsyncioTransport(dev_name, loop, callback=handler)
loop.run_forever()
finally:
loop.close()
我看到 CPU 使用率越来越高(大约 100%)。 我不明白为什么:模块收到的消息很少(每 5 秒约 1 条消息),我认为当 epoll_wait 被调用时 CPU 应该空闲,等待下一个活动。
我用 python cProfile 启动了主程序,它显示了这个:
In [4]: s.sort_stats('time', 'module').print_stats(50)
Mon Jul 20 22:20:55 2015 rfxcom_profile.log
263629453 function calls (263628703 primitive calls) in 145.437 seconds
Ordered by: internal time, file name
List reduced from 857 to 50 due to restriction <50>
ncalls tottime percall cumtime percall filename:lineno(function)
13178675 37.280 0.000 141.337 0.000 /usr/local/lib/python3.4/asyncio/base_events.py:1076(_run_once)
13178675 31.114 0.000 53.230 0.000 /usr/local/lib/python3.4/selectors.py:415(select)
13178674 15.115 0.000 32.253 0.000 /usr/local/lib/python3.4/asyncio/selector_events.py:479(_process_events)
13178675 12.582 0.000 12.582 0.000 {method 'poll' of 'select.epoll' objects}
13178699 11.462 0.000 17.138 0.000 /usr/local/lib/python3.4/asyncio/base_events.py:1058(_add_callback)
13178732 6.397 0.000 11.397 0.000 /usr/local/lib/python3.4/asyncio/events.py:118(_run)
26359349 4.872 0.000 4.872 0.000 {built-in method isinstance}
1 4.029 4.029 145.365 145.365 /usr/local/lib/python3.4/asyncio/base_events.py:267(run_forever)
13178669 4.010 0.000 4.913 0.000 /home/bruno/src/DomoPyc/venv/lib/python3.4/site-packages/rfxcom-0.3.0-py3.4.egg/rfxcom/transport/asyncio.py:85(_writer)
因此,就运行时间而言,前三个函数调用是 python3.4/asyncio/base_events.py
、python3.4/selectors.py
和 python3.4/asyncio/selector_events.py
。
EDIT :类似 运行 的时间命令给出:
time python -m cProfile -o rfxcom_profile.log rfxcom_profile.py
real 2m24.548s
user 2m19.892s
sys 0m4.113s
谁能解释一下为什么?
EDIT2: 由于fonctions调用的次数非常多,我跟踪了一下流程,发现有epoll_wait 上的循环,超时值为 2 毫秒:
// many lines like this :
epoll_wait(4, {{EPOLLOUT, {u32=7, u64=537553536922157063}}}, 2, -1) = 1
我在base_event._run_once看到有计算超时时间,但我想不通。我不知道如何将此超时设置得更高以降低 CPU.
如果有人知道...
感谢您的回答。
我回答我的问题,因为它可能对其他人有用。
将环境变量 PYTHONASYNCIODEBUG
设置为 1 后,出现了如下几行:
DEBUG:asyncio:poll took 0.006 ms: 1 events
在 Rfxcom 库中,有一个带有队列的编写器机制,用于将数据推送到串行设备。意图是我认为 "asyncio, tell me when I can write, and then I'll flush the write queue"。所以有这样一行:
self.loop.call_soon(self.loop.add_writer, self.dev.fd, self._writer)
self.dev
是 Serial
class 实例,self.dev.fd
是串行文件描述符。
如the doc says"add_writer(fd, callback, *args) : Start watching the file descriptor for write availability"。
我认为串口设备总是可以写的所以我做了一个小脚本:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
loop = get_event_loop()
def writer_cb():
logger.info("writer cb called")
s = Serial('/dev/serial/by-id/usb-RFXCOM_RFXtrx433_A1XZI13O-if00-port0', 38400, timeout=1)
loop.add_writer(s.fd, writer_cb)
loop.run_forever()
并看到无限循环的行,使 CPU 达到 100%:
DEBUG:asyncio:poll took 0.006 ms: 1 events
INFO:root:writer cb called
所以我觉得没必要写writer callback,直接在串口设备上调用write
即可