Как правильно использовать многопоточность в python? - PullRequest
0 голосов
/ 06 апреля 2020

Недавно я начал изучать многопоточность и хотел реализовать ее в следующем коде.

import timeit
start = timeit.default_timer()
def func(num):
    s = [(i, j, k) for i in range(num) for j in range(num) for k in range(num)]
    return s
z = 150
a,b = func(z),func(z)
print(a[:5], b[:5])
stop = timeit.default_timer()
print("time: ", stop - start)

время, которое потребовалось:

time:  3.7628489000000003

Поэтому я попытался использовать модуль Threading и изменил код следующим образом:

import timeit
from threading import Thread
start = timeit.default_timer()


def func(num):
    s = [(i, j, k) for i in range(num) for j in range(num) for k in range(num)]
    print(s[:5])

a = Thread(target=func, args=(150,))
b = Thread(target=func, args=(150,))
a.start()
b.start()
a.join()
b.join()
stop = timeit.default_timer()
print("time: ", stop - start)

время, которое потребовалось:

time:  4.2522736

Но вместо этого он должен уменьшиться вдвое, а увеличиться. Что-то не так в моей реализации? Пожалуйста, объясните, что пошло не так или есть лучший способ добиться этого.

1 Ответ

0 голосов
/ 06 апреля 2020

Вы столкнулись с так называемой Глобальной блокировкой интерпретатора, GIL для краткости.

Потоки в python не являются "реальными" потоками, то есть они не выполняются одновременно, а атомируются c операции в них вычисляются последовательно в некотором порядке (этот порядок часто трудно предопределить)

Это означает, что потоки библиотеки threading полезны, когда вам нужно одновременно ожидать много блокирующих вещей. Обычно это прослушивание сетевого подключения, когда один поток находится с receive() -методом, пока что-то не получено. Другие потоки могут продолжать делать другие вещи и не должны постоянно проверять соединение. Реальный прирост производительности, однако, не может быть достигнут с помощью threading

. Существует еще одна библиотека, называемая multiprocessing, которая реализует реальные потоки, которые фактически выполняются одновременно. Использование multiprocessing во многом похоже на библиотеку threading, но требует немного больше работы и заботы. Я осознал, что этот разрыв между threading и multiprocessing - хорошая и полезная вещь. Все потоки в threading имеют доступ к одному и тому же полному пространству имен, и до тех пор, пока рассматриваются условия гонки, они работают в одной и той же вселенной.

Потоки в multiprocessing (я должен использовать здесь термин process ) с другой стороны, разделены пропастью различных пространств имен после запуска дочернего процесса. При передаче информации между ними необходимо использовать специализированные очереди связи и объекты общего пространства имен. Это быстро потребует сотен строк стандартного кода.

...