0

我一直在对这个主题进行一些搜索,但我的问题似乎没有一个非常明确的答案。我目前正在做一个项目,用户单击一个按钮,一旦他调用一个python函数reply(),该函数就会启动两个不同的线程,a(代表音频)和r(代表例程)这两个线程应该一起工作并且基本上根据叙述者的讲话指向地图中的一个方向:

def reply(index, path2, path3):
    a = threading.Thread(target=playaudio(path3))
    r = threading.Thread(target=routine(path2))
    r.start()
    a.start()

我想知道是否有一种方法可以访问该函数并在用户单击停止按钮时为playaudioroutine函数停止这些线程,这样如果用户不再想看到它,他需要做的就是停止演示. 两个函数设置如下:

# play audio function starts here:
def playaudio(path):
    try:
        subprocess.Popen(["mpg123", path])

    except Exception as ex:
        tkMessageBox.showinfo('Error', 'An error occurred.  ' + str(ex))

# routine function starts here
# routine controls the servo module
def routine(path):
    with open(path, 'rb') as f:
        reader = csv.reader(f)
        settings = list(reader)

    print(settings)
    i = 1
    while i < (len(settings) - 1):
        try:
            setall(int(settings[i][1]), int(settings[i][2]), int(settings[i][3]), int(settings[i][4]))
            delay = float(settings[i+1][0]) - float(settings[i][0]) - 0.015 #includes processing time
            time.sleep(delay)
            i += 1
        except Exception as ex:
            pass
    setall(int(settings[i][1]), int(settings[i][2]), int(settings[i][3]), int(settings[i][4]))

这些将通过Tkinter.Button主屏幕上的元素启动,并将播放音频和控制伺服模块。

button = Tkinter.Button(window, text='Audio 4', command=lambda: reply(1, 'path/to/excel/file.csv', '/path/to/audio/file.mp3'))
button.config(width="30", height="5")
button.place(x=490, y=40)

对于停止功能,我认为添加另一个按钮元素是一种解决方案,但在用户单击它时Tkinter使用不同的功能退出。subprocess

stop_button = Tkinter.Button(window, text='Stop Audio', command=lambda: stop())
stop_button.config(width="30", height="5")
stop_button.place(x=490, y=360)

对于实际stop()功能,我尝试了一些方法,例如stop()destroy()但音频或伺服继续运行,或者实际程序关闭。

所以我的问题是,我应该做些什么不同的事情?我真的很感激这个问题的任何反馈。

4

1 回答 1

1

你看过队列模块吗?您可以使用它向线程发送消息。

所以,假设你有q(一个实例Queue)可以被你的线程函数访问,你的routine()线程函数可能看起来像这样:

def routine(path):

    # skip some stuff...

    while i < (len(settings) - 1):
        if not q.empty():
            message = q.get()
            if message == 'stop':
                break

        # rest of your function

在您的playaudio()函数中,您需要保留Popen您创建的对象并使用 `terminate() 方法来结束该过程。查看子流程文档以获取有关如何执行此操作的更多信息。

然后,当用户单击“停止”按钮时,您可以向队列发布消息:

def stop():
    q.put('stop')

顺便说一句,看看多进程模块。Python 的 GIL 会阻止线程正常发生,而多进程能够绕过这个问题并利用多个内核。

于 2017-06-28T18:39:31.137 回答