(Python)使用线程通过getch查找键输入 [英] (Python) Using threading to look for key input with getch

查看:101
本文介绍了(Python)使用线程通过getch查找键输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图写一段测试代码,它会不断打印Running直到按下一个键。我试图通过创建一个监听按键的附加线程(称为thread1)来实现这一点。



当我运行我的代码时,线程启动正常,并且似乎执行正常,直到调用getch.getch()。虽然getch.getch()正在等待按键,但它似乎不仅停止了thread1,而且还停止了主线程。



我如何确保在thread1侦听按键时主线程继续运行?



我'使用python 2.7和getch 1.0( https://pypi.python.org/pypi/getch 这是我的代码:

  import threading 
导入时间
import getch

class myThread(threading.Thread):
def __init __(self,threadID,name,cont):
threading.Thread .__ init__ (self)
self.threadID = threadID
self.name = name
self.cont = cont

def run(self):
print开始+ self.name +\ n
打印等待2秒
time.sleep(2)
char = getch.getch()
打印'你按%s'%char
cont.append(1)
打印终止+ self.name

cont = []

$ b thread1 = myThread(1,Thread1,续)

thread1.start()

而cont == []:
printRunning
time.sleep(0.5)

它输出:

 开始Thread1 
运行

等待2秒
运行
运行
运行

它一直待到我按下一个键

解决方案

你正在打这个问题是因为GIL。如果您使 threading.Thread a multiprocessing.Process


$,它可以正常工作b $ b

  class myThread(multiprocessing.Process):
def __init __(self,threadID,name,cont):
super(myThread,self)。 __init __()
#threading.Thread .__ init __(self)
self.threadID = threadID
self.name = name
self.cont = contdef run(self):
printStarting+ self.name +\ n
char = getch.getch()
print'你按%s'%char
cont.append(1)
打印终止+ self.name

cont = []

thread1 = myThread(1,Thread1,续)

thread1.start()

而cont == []:
printRunning
time.sleep(0.5)

输出:

  dan @ dantop:〜 $ ./get.py 
运行
开始Thread1

运行
运行
运行
运行
运行
运行
运行
运行
你按下f
终止线程1
运行
运行
运行
运行
运行
运行
运行
运行

getch 是一个C-extension,正在阻止调用 getchar(),但它不会首先释放GIL 。因为Python实际上不能同时运行两个线程,所以它会卡在工作线程中,等待阻塞对 getchar()的调用。



通过使用 Py_BEGIN_THREADS getch C扩展代码显式释放GIL,您可以非常轻松地修复此错误$ c>和 Py_ALLOW_THREADS

  static PyObject * getch_getche(PyObject * self,PyObject * args)
{
int ok = PyArg_ParseTuple(args,);
char c;
Py_BEGIN_ALLOW_THREADS
c = getche();
Py_END_ALLOW_THREADS
返回PyUnicode_FromFormat(%c,c);
}

静态PyObject * getch_getch(PyObject * self,PyObject * args)
{
int ok = PyArg_ParseTuple(args,);
char c;
Py_BEGIN_ALLOW_THREADS
c = getch();
Py_END_ALLOW_THREADS
返回PyUnicode_FromFormat(%c,c);
}

如果您将更改改为 getchmodule.c 并重建扩展,原始的,使用线程的示例代码工作正常。


I've been trying to write a piece of test code which will continually print "Running" until a key is pressed. I've tried to implement this by creating an additional thread (called thread1) that will listen for a keypress.

When I run my code, the thread launches fine, and seems to execute properly until getch.getch() is called. While getch.getch() is waiting for a keypress, it seems to stop not only thread1, but also the main thread.

How can I ensure that while thread1 listens for a keypress, the main thread keeps running?

I'm using python 2.7 and getch 1.0 (https://pypi.python.org/pypi/getch).

Here's my code:

import threading
import time
import getch

class myThread (threading.Thread):
    def __init__(self, threadID, name, cont):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.cont = cont

    def run(self):
        print "Starting " + self.name +"\n"
        print "waiting 2 seconds"
        time.sleep(2)
        char = getch.getch()
        print 'You pressed %s' % char
        cont.append(1)
        print "Terminating" + self.name

cont = []

thread1 = myThread(1, "Thread1", cont)

thread1.start()

while cont == []:
    print "Running"
    time.sleep(0.5)

It outputs this:

Starting Thread1
Running

waiting 2 seconds
Running
Running
Running

And it stays there until I press a key

解决方案

You're hitting this issue because of the GIL. It works fine if you make the threading.Thread a multiprocessing.Process:

class myThread (multiprocessing.Process):
    def __init__(self, threadID, name, cont):
        super(myThread, self).__init__()
        #threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.cont = contdef run(self):
        print "Starting " + self.name +"\n"
        char = getch.getch()
        print 'You pressed %s' % char
        cont.append(1)
        print "Terminating" + self.name

cont = []

thread1 = myThread(1, "Thread1", cont)

thread1.start()

while cont == []: 
    print "Running"
    time.sleep(0.5)

Output:

dan@dantop:~$ ./get.py 
Running
Starting Thread1

Running
Running
Running
Running
Running
Running
Running
Running
You pressed f
TerminatingThread1
Running
Running
Running
Running
Running
Running
Running
Running

getch is a C-extension, and is doing a blocking call to getchar(), but it doesn't release the GIL first. Because Python cannot actually run two threads concurrently, it gets stuck in the worker thread waiting for blocking call to getchar().

You can actually fix this bug pretty easily, by explicitly releasing the GIL from the getch C-extension code, using Py_BEGIN_THREADS and Py_ALLOW_THREADS:

static PyObject *getch_getche(PyObject *self, PyObject *args)
{
    int ok = PyArg_ParseTuple(args, "");
    char c;
    Py_BEGIN_ALLOW_THREADS
    c = getche();
    Py_END_ALLOW_THREADS
    return PyUnicode_FromFormat("%c", c); 
}

static PyObject *getch_getch(PyObject *self, PyObject *args)
{
    int ok = PyArg_ParseTuple(args, "");
    char c;
    Py_BEGIN_ALLOW_THREADS
    c = getch();
    Py_END_ALLOW_THREADS
    return PyUnicode_FromFormat("%c", c); 
}

If you make that change to getchmodule.c and rebuild the extension, the original, thread-using, example code works fine.

这篇关于(Python)使用线程通过getch查找键输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆