[英]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.