Они будут работать одновременно, но не параллельно. ОС будет часто переключаться между двумя потоками, чтобы они оба могли выполнять свою работу. Это то, что подразумевается под «одновременным»; одному потоку не нужно ждать завершения другого, прежде чем он сможет начать работу. Но из-за GIL они никогда не будут работать одновременно в одно и то же время, когда каждый из них будет работать на разных ядрах параллельно. Каждый поток будет работать какое-то время, приостанавливаться, пока работает другой поток, затем снова запускаться, затем приостанавливаться и т. д.
Это достаточно легко увидеть, если вы просто запустите код примера. Вот вывод на моей машине:
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
hello
hi
Ясно, что оба потока работают. Просто каждый поток работает медленнее, чем если бы в программе работал только один поток.
Рассмотрим этот пример, где каждый поток вычисляет последовательность Фибоначчи:
import thread
import time
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
def test():
while True:
start = time.time()
out = fib(32)
print "hello %s: %s" % (out, str(time.time() - start))
def test2():
while True:
out = fib(20)
def start_thread():
try:
thread.start_new_thread( test2,() )
except:
print "Error: Unable to start thread"
#start_thread()
test()
Когда работает только test
(поэтому второго потока нет), я получаю следующий вывод:
hello 2178309: 0.953778982162
hello 2178309: 0.954975128174
hello 2178309: 0.95578789711
hello 2178309: 0.949182033539
Если я также запускаю test2
в фоновом режиме, я получаю следующее:
hello 2178309: 4.07990288734
hello 2178309: 4.08523893356
hello 2178309: 2.51651597023
hello 2178309: 2.13291287422
hello 2178309: 2.19885015488
Как видите, производительность сильно страдает.
Обратите внимание: если один из потоков делает что-то, что освобождает GIL, например, блокирует ввод-вывод или обращается к библиотеке C, которая освобождает GIL, вы не увидите такого снижения производительности, потому что в этом случае фактически оба потока может работать параллельно. Это неприменимо в приведенном выше примере, поскольку ни один из потоков не выполняет работу, которая освобождает GIL.
person
dano
schedule
17.04.2015