范围规则和线程

时间:2011-07-21 00:28:19

标签: python

这是有效的程序(我能够听到正在发言的文本):

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()。

希望我有道理

由于

1 个答案:

答案 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语言编写的库)都支持线程,因此您必须小心,阅读文档或询问作者。