簡體   English   中英

Python線程僅在從另一個模塊調用時才有效

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

我正在開發一個可從Kivy應用程序中接受MIDI鍵盤輸入(使用Mido)的應用程序。 目標是擁有一個線程,該線程不斷輪詢MIDI輸入並將事件路由到pyfluidsynth,而傳統的Kivy應用程序正在並行運行。 我需要某種並行過程,否則Kivy UI會凍結,直到運行循環時進行midi poll。

經過多番擺弄后,我開始使用它了,但是我對代碼有些擔心。 我嘗試在[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線程,此時會執行from mido_midi import start_synth, KeyboardInput和“ testing”行。 if __name__ == "__main__":是一種構造,旨在防止在導入包含該構造的文件時發生這種情況。 另外,請注意,您有兩個不同的KeyboardInput實例。 不確定這是否是您的意圖。

您只要能夠在if __name__ == "__main__":塊中添加相同的兩行,就可以啟動該線程:

m = KeyboardInput()
m.start()

如果您確實只想要KeyboardInput一個實例,則應該能夠

self.midikeyboard.start()

GameWidget __init__()方法中。

另外,如果您想更輕松地關閉,請在構造函數調用中添加daemon=True ,或者:

m = KeyboardInput(daemon=True)   

要么

self.midikeyboard = KeyboardInput(daemon=True)

daemon=True表示該線程將在應用程序完成后立即終止。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM