簡體   English   中英

用於播放不同聲音的音頻的python線程,似乎沒有正確鎖定,並且在線程調用之后函數的開始返回

[英]python threads for audio playing different sounds, do not seem to be locking correctly, and beginning of function returned to after thread calls

我正在研究基於鍵盤輸入從計算機播放聲音的代碼。 聲音存儲為wav文件並與PyAudio一起播放。 然而,為兩個連續的鍵盤敲擊播放的聲音之間的延遲太慢,所以我試圖添加線程以加快I / O時間。 但是,音頻現在變得沙啞,我不認為線程上的鎖是有效的。 這是相關代碼:

while threading.activeCount() < NUM_THREADS:
   message, delta_time = midi_in.get_message()
   if message:
    if message[2] == 0:
     continue
    elif message and (str(message[1]) == "108" or str(message[1]) == "107"):
     break
    else:
     t = threading.Thread(target=play, args=(message,))
     lock = threading.Lock()

     lock.acquire()
     t.start()
     lock.release()



def play(message):

  WAVE_FILENAME = "final"+str(message[1]) + '.wav'
  CHUNK = 1024
  wf = wave.open(WAVE_FILENAME)
  p = pyaudio.PyAudio()

  stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                 channels = wf.getnchannels(),
             rate = wf.getframerate(),
                 output = True)
  data = wf.readframes(CHUNK)
  while data != '':
   stream.write(data)
   data = wf.readframes(CHUNK)

  stream.stop_stream()
  stream.close()

  p.terminate()

非常感謝你的幫助!

我不認為線程上的鎖是有效的

原因是以下內容創建了一個新鎖:

lock = threading.Lock()

換句話說,您不是在循環的迭代中使用相同的鎖; 每次迭代都有自己的鎖。 結果,不發生同步。

我假設您必須將鎖傳遞給您的工作線程,如下所示:

def play(message, lock):
    lock.acquire()
    # do something with a restricted ressource 
    lock.release()

然后啟動一個線程並傳入鎖:

t = threading.Thread(target=play, args=(message, lock))

這里至少有兩個問題。

首先,正如NPE解釋的那樣,您正在為每個線程創建一個不同的鎖。 獲取鎖只會使您與獲取相同鎖的其他線程同步,而不是任何鎖。

其次,正如Theodros Zelleke所解釋的那樣,你實際上並沒有獲得工人線程中的鎖定; 你只是鎖定主線程,而它正在創建線程。 這沒有任何好處。

如果要確保一次只能運行一個線程,則需要執行以下操作:

lock = threading.Lock()
while threading.activeCount() < NUM_THREADS:
    message, delta_time = midi_in.get_message()
    if message:
        if message[2] == 0:
            continue
        elif message and (str(message[1]) == "108" or str(message[1]) == "107"):
            break
    else:
        t = threading.Thread(target=play, args=(message, lock))
        t.start()

def play(message, lock):
    WAVE_FILENAME = "final"+str(message[1]) + '.wav'
    CHUNK = 1024
    wf = wave.open(WAVE_FILENAME)
    p = pyaudio.PyAudio()

    with lock:
        stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                        channels = wf.getnchannels(),
                        rate = wf.getframerate(),
                        output = True)
        data = wf.readframes(CHUNK)
        while data != '':
            stream.write(data)
            data = wf.readframes(CHUNK)

        stream.stop_stream()
        stream.close()

請注意,我使用with lock:而不是顯式lock.acquire()lock.release() 這不僅僅是方便 - 如果您在鎖定下執行任何操作都會拋出異常,則lock.release()永遠不會被調用,除非您使用with語句或try

如果你想阻止主線程,以及所有play線程,你可以恢復你現有的鎖碼(或者更好,將它改為with lock:塊),但要確保你把鎖定放在你實際的位置想要它。

同時:你意識到,如果你做對了,你將會實現一個無限積壓的單聲道合成器,所以直到之前的聲音全部完成才能播放聲音? 這是解決延遲問題的一種補充方法......

在我做的時候還有一些評論:

  • 你為什么要做if message and … if message:
  • 你為什么要做str(message[1]) == "108"而不僅僅是message[1] == 108

暫無
暫無

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

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