Python线程仅在从另一个模块调用时工作

Python线程仅在从另一个模块调用时工作,python,kivy,python-multithreading,midi,Python,Kivy,Python Multithreading,Midi,我正在开发一个应用程序,该应用程序在Kivy应用程序中使用Mido接受MIDI键盘输入。目标是让一个线程不断轮询MIDI输入并将事件路由到PyFluidSync,而传统的Kivy应用程序正在并行运行。我需要某种并行处理,否则KivyUI会在循环运行时冻结midi轮询 在做了很多修改之后,我让它开始工作了,但我有点担心代码。我尝试在[if name==main]下启动线程,但只能运行一个进程,然后运行另一个进程 然后,由于意外,我在mido_midi.py中留下了最后两行代码,从而获得了预期的效果

我正在开发一个应用程序,该应用程序在Kivy应用程序中使用Mido接受MIDI键盘输入。目标是让一个线程不断轮询MIDI输入并将事件路由到PyFluidSync,而传统的Kivy应用程序正在并行运行。我需要某种并行处理,否则KivyUI会在循环运行时冻结midi轮询

在做了很多修改之后,我让它开始工作了,但我有点担心代码。我尝试在[if name==main]下启动线程,但只能运行一个进程,然后运行另一个进程

然后,由于意外,我在mido_midi.py中留下了最后两行代码,从而获得了预期的效果,这两行代码最初只是用于测试。现在,当我运行main.py时,我会得到应用程序和键盘输入。当我关闭应用程序时,除了一些丑陋的行为外,事情似乎按照我想要的方式进行

我担心的是,通过调用main中的所有内容,我似乎无法使线程正常工作。因为一切都在运转,我不明白为什么,我觉得这是不对的。我想我会把它扔给更聪明的人来获得洞察力

我做得对吗?如果没有,我需要改变什么?谢谢

main.py:

from kivy.app import App
from kivy.uix.widget import Widget
from mido_midi import start_synth, KeyboardInput

class MyApp(App):
    def build(self):
        return GameWidget()

class GameWidget(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        ...
        self.midikeyboard = KeyboardInput()
        ...

if __name__ == "__main__":
    app = MyApp()
    app.run()
mido_midi.py:

import mido
import fluidsynth
import threading

def start_synth(driver, sound, channel=0):
    fs = fluidsynth.Synth(samplerate=24000, gain=0.8)
    fs.start(driver)
    sfid = fs.sfload(sound)
    fs.program_select(channel, sfid, 0, 0)
    # print("Midi loaded...")
    return fs

class KeyboardInput(threading.Thread):
    def __init__(self, device='Keystation 88 Port 1', driver='coreaudio', sound='sounds/Wii_Grand_Piano.sf2', channel=0):
        super(KeyboardInput, self).__init__()
        self.played_notes = []
        self.device = device
        self.driver = driver
        self.sound = sound
        self.channel = channel
        self.inport = mido.open_input(self.device)
        self.fs = start_synth(self.driver, self.sound)

    def run(self):
        for msg in self.inport:
            print(msg)
            note = msg.note
            velocity = msg.velocity
            self.fs.noteon(self.channel, note, velocity)

# Code outside of the class, intended for testing
m = KeyboardInput()
m.start()
当您执行from mido_midi import start_synth时,您的代码正在启动KeyboardInput线程,此时将执行KeyboardInput和测试行。if _uname _==\u_umain _u;:是一个构造,旨在防止在导入包含该构造的文件时发生这种情况。另外,请注意,您有两个不同的键盘输入实例。不确定这是否是你的意图

只需在if _uname _u==\u_umain _u;:块中添加相同的两行,就可以启动该块中的线程:

m = KeyboardInput()
m.start()
如果你真的只需要一个键盘输入实例,你应该可以这样做

self.midikeyboard.start()
在GameWidget中的_init__方法中

此外,如果希望更轻松地关闭,请在构造函数调用中添加daemon=True,或者:

m = KeyboardInput(daemon=True)   

daemon=True意味着一旦应用程序完成,线程就会被终止

self.midikeyboard = KeyboardInput(daemon=True)