这是有效的程序(我能够听到正在发言的文本):
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()。
希望我有道理
由于
答案 0 :(得分: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
对象做其他不喜欢的事情时,这才会有所帮助。从您的代码看起来不像是这样,所以您可能不得不忍受在线程中创建每个引擎对象,并找到另一种传递状态的方法。或者,您可以将engine
保留在主线程中,并使用队列从其他线程中调用来进行其他工作。
值得记住的是,并非所有Python库(尤其是那些用C语言编写的库)都支持线程,因此您必须小心,阅读文档或询问作者。