高效的python raw_input和串口轮询

时间:2014-07-15 17:23:57

标签: python multithreading serial-port polling raw-input

我正在研究一个python项目,该项目轮询COM端口上的数据并轮询用户输入。截至目前,该计划正在顺利运作,但似乎效率低下。我在一个单独的线程中运行的while循环中发生了串行端口轮询,并将数据粘贴到队列中。用户输入轮询也发生在一个while循环中,该循环在一个单独的线程中运行,该输入将输入粘贴到队列中。不幸的是,我有太多的代码和帖子,它会从问题的角度来看。

那么是否有更有效的方法来轮询串行或raw_input()而不将它们放在无限循环中并在自己的线程中运行它们?

我一直在对这个主题进行大量研究,并不断遇到“单独的线程和队列”范例。但是,当我运行这个程序时,我在四核i7上使用了近30%的CPU资源。必须有更好的方法。

我曾在C中使用过ISR,并希望有类似于我可以使用的中断。我最近的研究发现了许多带有回调的“事件”库,但我似乎无法理解它们如何适应我的情况。我正在使用Windows 7(64位)计算机进行开发,但是当我完成时将成品移动到RPi。我不是在寻找代码,我只需要指向正确的方向。感谢您提供任何信息。

1 个答案:

答案 0 :(得分:5)

您看到CPU使用率很高,因为您的主线程正在使用非阻塞get_nowait调用在无限循环中轮询两个不同的队列,这意味着您的循环将大部分时间不断循环。不断运行循环使用CPU周期,就像任何紧密的无限循环一样。为了避免使用大量CPU,您希望让无限循环使用阻塞I / O,以便它们等到实际要处理的数据再继续之前。这样,您就不会经常运行循环,因此使用CPU。

所以,用户输入线程:

while True:
    data = raw_input() # This blocks, and won't use CPU while doing so
    queue.put({'type' : 'input' : 'data' : data})

COM线程:

while True:
    data = com.get_com_data()  # This blocks, and won't use CPU while doing so
    queue.put({'type' : 'COM' : 'data' : data})

主线程:

while True:
    data = queue.get() # This call will block, and won't use CPU while doing so
    # process data

阻止get调用只会等到另一个线程中put使用threading.Condition对象唤醒它。这不是重复的民意调查。来自Queue.py

# Notify not_empty whenever an item is added to the queue; a
# thread waiting to get is notified then.
self.not_empty = _threading.Condition(self.mutex)

...

def get(self, block=True, timeout=None):
    self.not_empty.acquire()
    try:
        if not block:
            if not self._qsize():
                raise Empty
        elif timeout is None:
            while not self._qsize():
                self.not_empty.wait()  # This is where the code blocks
        elif timeout < 0:
            raise ValueError("'timeout' must be a non-negative number")
        else:
            endtime = _time() + timeout
            while not self._qsize():
                remaining = endtime - _time()
                if remaining <= 0.0:
                    raise Empty
                self.not_empty.wait(remaining)
        item = self._get()
        self.not_full.notify()
        return item
    finally:
        self.not_empty.release()

def put(self, item, block=True, timeout=None):
    self.not_full.acquire()
    try:
        if self.maxsize > 0:
            if not block:
                if self._qsize() == self.maxsize:
                    raise Full
            elif timeout is None:
                while self._qsize() == self.maxsize:
                    self.not_full.wait()
            elif timeout < 0:
                raise ValueError("'timeout' must be a non-negative number")
            else:
                endtime = _time() + timeout
                while self._qsize() == self.maxsize:
                    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Full
                    self.not_full.wait(remaining)
        self._put(item)
        self.unfinished_tasks += 1
        self.not_empty.notify()  # This is what wakes up `get`
    finally:
        self.not_full.release()