2011-07-21 102 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