This is my script
import threading
import os
class Say(threading.Thread):
def __init__(self, cmd):
super(Say, self).__init__()
self.cmd = cmd
def run(self):
os.system(self.cmd)
t1 = Say("afplay /System/Library/Sounds/Tink.aiff")
t2 = Say("afplay /System/Library/Sounds/Ping.aiff")
t1.start()
print("a")
t2.start()
print("b")
It appears that both starts are executed immediately. However, the sounds are not played in parallel but one after the other.
When running the following shell script
afplay /System/Library/Sounds/Tink.aiff &
afplay /System/Library/Sounds/Ping.aiff &
both sounds play at the same time. What makes Python run the commands sequentially instead of parallel?
I'm using Big Sur with with the standard Python (2.7).
I suspect the issue here is Python's Global Interpreter Lock (GIL). In particular I'm guessing that when os.system
is called in t1
, the GIL locks and doesn't unlock until the command returns, preventing t2
from running any python code.
If I replace
os.system(self.cmd)
with
subprocess.Popen(['bash', '-c', self.cmd])
then the problem goes away.
For that matter, since you are spawning separate processes at any event and doing nothing with their output, there is no point in creating all these threads; you can get the same effect by replacing your entire code sample with
import subprocess
subprocess.Popen(['bash', '-c', "afplay /System/Library/Sounds/Tink.aiff"])
subprocess.Popen(['bash', '-c', "afplay /System/Library/Sounds/Ping.aiff"])