在其线程中停止PocketSphinx LiveSpeech

问题描述

我正在实现一个简单的Python应用程序,该应用程序在其自己的工作线程中从麦克风运行PocketSphinx识别,并将识别输出通过队列发送到运行Tkinter GUI的主线程。 在辅助线程中,有一个LiveSpeech迭代器类的for循环读取。

现在,当关闭Tkinter窗口时,我也想终止工作线程。问题是它在for循环中(在for phrase in self.__speech:中的行pocketsphinx_inmic.py处被阻塞,并且仅在麦克风有任何输入时才继续)。我想找到一种机制,允许我“解除阻止”并让我终止线程(即,在麦克风上没有任何输入)。有人可以建议我怎么做吗?

我正在尝试一些愚蠢的事情,例如尝试使用新的迭代器重写PocketSphinx_InMic .__ speech,希望它可以取消阻止读取,但是没有运气。我找不到LiveSpeech类的实现代码,这使其变得更加困难。 我什至会接受有关如何以某种肮脏的方式杀死线程的建议-这只是一个演示,没有生产代码...

完整代码如下。

pocketsphinx_inmic.py:

from pocketsphinx import Pocketsphinx,get_model_path,LiveSpeech
import nonblock_queue

class PocketSphinx_InMic:
    """ Wrapper class for PocketSphinx live recognition from a microphone. Shall be used as backend for the
    GUI demo application. """

    def __init__(self,queue):
        model_path = get_model_path()
        self.__config = {
            # ...
        }

        self.__speech = LiveSpeech(**self.__config)
        self.__queue = queue

    def recog_loop(self):
        for phrase in self.__speech:
            msg = str(phrase)
            self.__queue.enqueue(msg)

nonblock_queue.py:

import queue

class NonblockQueue:
    def __init__(self,size = None):
        if(size != None):
            self.__blck_queue = queue.Queue(maxsize = size)
        else:
            self.__blck_queue = queue.Queue()

    def enqueue(self,msg):
        self.__blck_queue.put(msg)

    def dequeue(self):
        ret = None
        try:
            ret = self.__blck_queue.get(False)
        except queue.Empty:
            pass
        
        return ret

...和主要代码

from pocketsphinx_inmic import PocketSphinx_InMic
import threading
import tkinter as tk
from tkinter import scrolledtext
from nonblock_queue import NonblockQueue
from time import sleep

def set_elem_grid(gui_elem,row_arg,col_arg):
    gui_elem.grid(row = row_arg,column = col_arg,padx = GRID_FRAME_PADX,pady = GRID_FRAME_PADY)

if __name__ == "__main__":
    print("Starting the main program...")
    
    window = tk.Tk()
    window.geometry("640x480")
    
    out_text = scrolledtext.ScrolledText(window,width = SCROLL_TEXT_WIDTH,height = SCROLL_TEXT_HEIGHT)
    set_elem_grid(out_text,0)

    thr_queue = NonblockQueue()
    sphinx = PocketSphinx_InMic(thr_queue)

    sphinx_thread = threading.Thread(target = sphinx.recog_loop)
    sphinx_thread.start()

    while(1):
        try:
            msg = thr_queue.dequeue()
            if(msg):
                out_text.insert(index = tk.INSERT,chars = str(msg) + "\n")
            window.update_idletasks()
            window.update()
            sleep(0.1)
        except:
            # if the window is closed,exception is thrown - just quit Now...
            # Todo: we shall kill the second thread gracefully!
            exit(0)

解决方法

找到LiveSpeech类的实现代码后,我发现有一个stop()方法。但是,它没有达到我的期望。 我最终用threading替换了multiprocessing,那里有一个标准的terminate()方法来终止进程。感觉像是一个过分的杀伤力,但完成了工作。