2014-06-12 26 views
4

我一直在試圖寫一段測試代碼,直到按下一個鍵,這將持續打印出「運行」鍵輸入。我試圖通過創建一個額外的線程(稱爲thread1)來實現這一點,該線程將監聽按鍵。(Python)的使用線程來尋找與殘培

當我運行我的代碼,該線程啓動罰款,並似乎正確地執行,直到getch.getch()被調用。雖然getch.getch()正在等待按鍵,但它似乎不僅停止了thread1,而且還停止了主線程。

我怎樣才能確保在線程1偵聽按鍵,主線程繼續運行?

我使用python 2.7和1.0的getch(https://pypi.python.org/pypi/getch)。

這裏是我的代碼:

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) 

它輸出這樣的:

Starting Thread1 
Running 

waiting 2 seconds 
Running 
Running 
Running 

直到我按一個鍵

回答

3

你打,因爲GIL的這個問題,它在那裏停留。如果你把它工作正常的threading.Thread一個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) 

輸出:

[email protected]:~$ ./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是C的擴展,並且正在做一個阻塞調用getchar(),但它不釋放GIL第一。因爲Python不能真正運行兩個線程同時,它被卡在工作線程在等待阻塞調用getchar()

實際上,你可以修正這個錯誤很容易,通過明確從getch C的擴展代碼釋放GIL,用Py_BEGIN_THREADSPy_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); 
} 

如果你做出的改變,以getchmodule.c和重建的延長,原始的線程使用示例代碼工作正常。

+0

它大概打到吉爾因爲殘培是一種阻塞系統級調用不阻塞調用蟒蛇的raw_input ...是一個Python調用塊(但其蟒蛇水平調用)和工作正常,但我認爲殘培塊從OS級別而不是python –

+0

完美!那就是訣竅。儘管它沒有像應該那樣打破循環,但這是一個單獨的問題。謝謝! – user3735129

+0

@JoranBeasley是的,這是正確的。它在C-extension中阻塞而不釋放GIL。我更新了我的答案以解釋這個問題,以及如何解決它,如果需要。 – dano