2011-07-21 100 views
3

這是工作程序(我能聽到在行動文本到語音):範圍規則和線程

import pyttsx 
import threading 

def saythread(location, text): 

    engine = pyttsx.init() 

    engine.say(text) 
    engine.runAndWait() 


e = (1, "please work, oh my god") 
t = threading.Thread(target=saythread,args=e,name='sayitthread') 
t.start() 

如果程序改爲

import pyttsx 
import threading 
def saythread(location, text): 

    global engine    #(CHANGED) ADDED GLOBAL 

    engine.say(text) 
    engine.runAndWait()   

e = (1, "please work, oh my god") 

engine = pyttsx.init()     #(CHANGED) ADDED VARIABLE 
t = threading.Thread(target=saythread,args=e,name='sayitthread') 
t.start() 

然後獲取'卡住'在行「engine.runAndWait()」,文本到語音不起作用。我猜測問題在於線程範圍的規則。對? 基本上我想要的是..在我的主線程中引擎變量的'句柄'。所以我可以從主線程調用engine.stop()。

希望我是有道理的

感謝

回答

2

全局變量幾乎都是個不錯的辦法。您只需通過engine作爲參數傳遞給saythread

def saythread(engine, location, text): 
    engine.say(text) 
    engine.runAndWait()   

# ...later... 

engine = pyttsx.init()     #(CHANGED) ADDED VARIABLE 
t = threading.Thread(target=saythread,args=(engine, 1, "here we go"),name='sayitthread') 
t.start() 

我願意打賭,真正的問題是,你的engine對象的方法不被設計爲從其他線程調用。 (作用域無關吧,順便說一句,這取決於底層庫的設計。)

這可能是你能解決該問題用鎖得:

def saythread(engine, lock, location, text): 
    with lock: 
     engine.say(text) 
     engine.runAndWait() 

engine = pyttsx.init() 
lock = threading.Lock() 
t = threading.Thread(
     target=saythread, 
     args=(engine, lock, 1, "here we go"), 
     name='sayitthread') 
t.start() 

。 ..但這隻會有助於如果你正在與你不喜歡的其他對象同時做其他事情。從你的代碼看,情況並非如此,所以你可能需要在線程中創建每個引擎對象,並尋找另一種傳遞狀態的方法。或者,您可以將engine保留在主線程中,並使用隊列將以及其他正在執行其他工作的線程中調用。

值得一提的是,並不是所有的Python庫(尤其是那些用C編寫的庫)都支持線程,所以你必須小心,閱讀文檔或者問作者。

+1

謝謝你的時間。我試圖將引擎作爲參數傳遞,但沒有奏效。使用鎖定不起作用。但最後使用一個內部函數調用engine.stop()並使用隊列告訴內部函數何時停止,終於解決了我的問題!非常感謝!! –

+1

@ user161179 - 很高興聽到它!如果您只是爲了觸發單個事件而使用隊列,則可以使用['Condition]](http://docs.python.org/library/threading.html#condition-objects)或['事件'](http://docs.python.org/library/threading.html#event-objects)對象。 – detly