简体   繁体   English

Python线程仅在从另一个模块调用时才有效

[英]Python threading only working when called from another module

I am working on an app that accepts MIDI keyboard input (using Mido) from within a Kivy application. 我正在开发一个可从Kivy应用程序中接受MIDI键盘输入(使用Mido)的应用程序。 The goal is to have one thread that constantly polls the MIDI input and routes events to pyfluidsynth, while a conventional Kivy app is running in parallel. 目标是拥有一个线程,该线程不断轮询MIDI输入并将事件路由到pyfluidsynth,而传统的Kivy应用程序正在并行运行。 I need some sort of parallel process, or else the Kivy UI freezes for as long as the midi poll while loop is running. 我需要某种并行过程,否则Kivy UI会冻结,直到运行循环时进行midi poll。

After much fiddling, I got it to work, but I'm a bit concerned about the code. 经过多番摆弄后,我开始使用它了,但是我对代码有些担心。 I tried starting the threads under [if name == " main "], but was only ever able to run one process, followed by the other. 我尝试在[if name ==“ main ”]下启动线程,但是只能运行一个进程,然后再运行另一个进程。

Then by accident I was able to get the desired effect by leaving in the last 2 lines of code in mido_midi.py, which were originally just for testing. 然后偶然地,我通过将mido_midi.py的最后两行代码保留在原来仅用于测试的代码中,从而获得了预期的效果。 Now, when I run main.py, I get the app plus the keyboard input. 现在,当我运行main.py时,我得到了该应用程序以及键盘输入。 Other than some ugly behaviour when I close the app, things appear to be working the way I wanted. 除了我关闭应用程序时的某些丑陋行为外,其他事情似乎都按照我想要的方式工作。

My concern is that I can't seem to get the threading to work by calling everything from main. 我担心的是,我似乎无法通过从main调用所有内容来使线程正常工作。 Since things are working, and I don't understand why, and it looks wrong to me. 既然一切正常,我不明白为什么,对我来说,这似乎是错误的。 I thought I'd throw it to smarter people for insight. 我以为我会把它扔给更聪明的人以获得见识。

Am I doing it right? 我做对了吗? If not, what do I need to change? 如果没有,我需要更改什么? Thanks. 谢谢。

main.py: 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: 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()

Your code is starting the KeyboardInput thread when you do the from mido_midi import start_synth, KeyboardInput and the "testing" lines are executed at that time. 当您执行from mido_midi import start_synth, KeyboardInput您的代码正在启动KeyboardInput线程,此时会执行from mido_midi import start_synth, KeyboardInput和“ testing”行。 The if __name__ == "__main__": is a construct designed to prevent exactly that from happening when a file containing that construct is imported. if __name__ == "__main__":是一种构造,旨在防止在导入包含该构造的文件时发生这种情况。 Also, note that you have two different instance of KeyboardInput . 另外,请注意,您有两个不同的KeyboardInput实例。 Not sure if that is your intention. 不确定这是否是您的意图。

You should be able to start the thread inside your if __name__ == "__main__": block by just adding the same two lines inside that block: 您只要能够在if __name__ == "__main__":块中添加相同的两行,就可以启动该线程:

m = KeyboardInput()
m.start()

If you really only want one instance of KeyboardInput , you should be able to do 如果您确实只想要KeyboardInput一个实例,则应该能够

self.midikeyboard.start()

inside your __init__() method in GameWidget . GameWidget __init__()方法中。

Also, if you want easier shutdown add daemon=True to the constructor call, either: 另外,如果您想更轻松地关闭,请在构造函数调用中添加daemon=True ,或者:

m = KeyboardInput(daemon=True)   

or 要么

self.midikeyboard = KeyboardInput(daemon=True)

The daemon=True means that the thread will be killed as soon as the app is finished. daemon=True表示该线程将在应用程序完成后立即终止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当 function 在另一个模块中时,线程无法正常工作 - Threading not working properly when function is in another module 在python中,为什么只有在调用另一个模块的方法时才会执行类体中的代码? - In python,why does the code in class body gets executed only when a method of another module is called? 如果从main调用,Python模块不起作用? - Python module not working if called from main? 使用线程时使用Python更新导入模块的变量 - Update variable from imported module with Python when using Threading 从另一个文件夹中的脚本调用 Python 在同一文件夹中找不到模块 - Python not finding module in same folder when called from a script in another folder Obspy.read() 从 mod_python apache 模块调用时不起作用 - Obspy.read() not working when called from mod_python apache module python导入无法从一个模块到另一个模块 - python import not working from one module to another 实例化一个 static 变量,从 python 中的另一个模块调用 - Instantiate a static variable to be called from another module in python Python 从另一个调用时找不到模块 - Python module not found when calling from another 从命令行调用时找不到python模块 - python module cannot be found when called from command line
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM