python线程为音频播放不同的声音,似乎没有正确锁定,函数的开头在线程调用后返回

python线程为音频播放不同的声音,似乎没有正确锁定,函数的开头在线程调用后返回,python,multithreading,locks,Python,Multithreading,Locks,我正在编写代码,根据键盘的输入,从计算机中播放声音。声音存储为wav文件,并用PyAudio播放。但是,连续两次键盘敲击的声音之间的延迟太慢,因此我尝试添加线程以加快I/O时间。然而,现在的音频很刺耳,我认为线程上的锁不起作用。以下是相关代码: while threading.activeCount() < NUM_THREADS: message, delta_time = midi_in.get_message() if message: if message[2]

我正在编写代码,根据键盘的输入,从计算机中播放声音。声音存储为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()
换句话说,在循环的迭代过程中,您没有使用相同的锁;每个迭代都有自己的锁。因此,不会发生同步

我认为线程上的锁不起作用

原因是以下操作会创建一个新锁:

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))

我假设您必须将锁传递给工作线程,如下所示:

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

如果要阻止主线程以及所有播放线程,可以还原现有的锁代码,或者更好地将其更改为with lock:block,但请确保将锁放在实际需要的位置

同时:你意识到如果你做到了这一点,你将实现一个单声道合成器,有无限的积压工作,所以在之前的声音都完成之前没有声音可以播放?这是一种解决延迟问题的附加方法

在这里,我想再多说几句:

你为什么要在if消息和…内部if消息:? 你为什么要做strmessage[1]==108而不仅仅是message[1]==108?
这里至少有两个问题

首先,正如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

如果要阻止主线程以及所有播放线程,可以还原现有的锁代码,或者更好地将其更改为with lock:block,但请确保将锁放在实际需要的位置

同时:你意识到如果你做到了这一点,你将实现一个单声道合成器,有无限的积压工作,所以在之前的声音都完成之前没有声音可以播放?这是一种解决延迟问题的附加方法

在这里,我想再多说几句:

你为什么要在if消息和…内部if消息:? 你为什么要做strmessage[1]==108而不仅仅是message[1]==108?
作为旁注,间距使代码很难阅读。标准为缩进4个空格;2个空格仍然可读;任意混合使用1个空格、3个空格和制表符都是乱七八糟的。顺便说一句,你的空格让你的代码很难阅读。标准为缩进4个空格;2个空格仍然可读;任意混合使用1个空格、3个空格和制表符简直是一团糟。感谢您的帮助和代码建议。我之所以设置锁定,是为了确保每个音频片段的播放不会干扰其他音频片段,这样在所有之前的声音播放完毕之前,都不会播放任何声音。似乎在播放o的声音之间有重叠
ut-声音变得模糊/爆裂,质量不是很好。我认为这是在计算机上竞争I/O资源的问题。你知道有什么好办法吗?事实上,我刚刚用pygame的软件让音频工作得更干净了mixer@user1201163:是的,使用混音器可能是解决更高层次问题的正确方法。我们都应该解决这个问题,而不仅仅是试图解释你的锁出了什么问题。谢谢你的帮助和代码建议。我之所以设置锁定,是为了确保每个音频片段的播放不会干扰其他音频片段,这样在所有之前的声音播放完毕之前,都不会播放任何声音。如果播放的声音之间有重叠,则声音会变得模糊/噼啪作响,质量也不是很好。我认为这是在计算机上竞争I/O资源的问题。你知道有什么好办法吗?事实上,我刚刚用pygame的软件让音频工作得更干净了mixer@user1201163:是的,使用混音器可能是解决更高层次问题的正确方法。我们都应该解决这个问题,而不是仅仅试图解释你的锁出了什么问题。