python线程为音频播放不同的声音,似乎没有正确锁定,函数的开头在线程调用后返回
我正在编写代码,根据键盘的输入,从计算机中播放声音。声音存储为wav文件,并用PyAudio播放。但是,连续两次键盘敲击的声音之间的延迟太慢,因此我尝试添加线程以加快I/O时间。然而,现在的音频很刺耳,我认为线程上的锁不起作用。以下是相关代码: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]
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:是的,使用混音器可能是解决更高层次问题的正确方法。我们都应该解决这个问题,而不是仅仅试图解释你的锁出了什么问题。