Документация по Python

Процессы и потоки

В: Документация по Python

Введение

Примеры

Глобальная блокировка интерпретатора

Python производительность многопоточной часто страдает из - за глобальным интерпретатор Замка . Короче говоря, даже если вы можете иметь несколько потоков в программе Python, только одна инструкция байт-кода может выполняться параллельно в любое время, независимо от количества процессоров.

Таким образом, многопоточность в случаях, когда операции блокируются внешними событиями, такими как доступ к сети, может быть довольно эффективной:

 import threading
import time


def process():
    time.sleep(2)


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.00s
# Out: Four runs took 2.00s 

Обратите внимание , что даже если каждый process занимает 2 секунды , чтобы выполнить эти четыре процесса вместе были в состоянии эффективно работать параллельно, принимая всего 2 секунды.

Тем не менее, многопоточность в тех случаях, когда в коде Python выполняются интенсивные вычисления, такие как много вычислений, не приводит к значительным улучшениям и даже может быть медленнее, чем параллельная работа:

 import threading
import time


def somefunc(i):
    return i * i

def otherfunc(m, i):
    return m + i

def process():
    for j in range(100):
        result = 0
        for i in range(100000):
            result = otherfunc(result, somefunc(i))


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.05s
# Out: Four runs took 14.42s 

В последнем случае многопроцессорная обработка может быть эффективной, поскольку несколько процессов могут, конечно, выполнять несколько инструкций одновременно:

 import multiprocessing
import time


def somefunc(i):
    return i * i

def otherfunc(m, i):
    return m + i

def process():
    for j in range(100):
        result = 0
        for i in range(100000):
            result = otherfunc(result, somefunc(i))


start = time.time()
process()
print("One run took %.2fs" % (time.time() - start))


start = time.time()
processes = [multiprocessing.Process(target=process) for _ in range(4)]
for p in processes:
    p.start()
for p in processes:
    p.join()
print("Four runs took %.2fs" % (time.time() - start))

# Out: One run took 2.07s
# Out: Four runs took 2.30s 

Запуск в нескольких потоках

Используйте threading.Thread запустить функцию в другом потоке.

 import threading
import os

def process():
    print("Pid is %s, thread id is %s" % (os.getpid(), threading.current_thread().name))

threads = [threading.Thread(target=process) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()

# Out: Pid is 11240, thread id is Thread-1
# Out: Pid is 11240, thread id is Thread-2
# Out: Pid is 11240, thread id is Thread-3
# Out: Pid is 11240, thread id is Thread-4 

Запуск в нескольких процессах

Используйте multiprocessing.Process для запуска функции в другом процессе. Интерфейс похож на threading.Thread :

 import multiprocessing
import os

def process():
    print("Pid is %s" % (os.getpid(),))

processes = [multiprocessing.Process(target=process) for _ in range(4)]
for p in processes:
    p.start()
for p in processes:
    p.join()

# Out: Pid is 11206
# Out: Pid is 11207
# Out: Pid is 11208
# Out: Pid is 11209 

Совместное использование состояния между потоками

Поскольку все потоки выполняются в одном и том же процессе, все потоки имеют доступ к одним и тем же данным.

Однако одновременный доступ к общим данным должен быть защищен блокировкой, чтобы избежать проблем с синхронизацией.

 import threading

obj = {}
obj_lock = threading.Lock()

def objify(key, val):
    print("Obj has %d values" % len(obj))
    with obj_lock:
        obj[key] = val
    print("Obj now has %d values" % len(obj))

ts = [threading.Thread(target=objify, args=(str(n), n)) for n in range(4)]
for t in ts:
    t.start()
for t in ts:
    t.join()
print("Obj final result:")
import pprint; pprint.pprint(obj)

# Out: Obj has 0 values
# Out:  Obj has 0 values
# Out: Obj now has 1 values
# Out: Obj now has 2 valuesObj has 2 values
# Out: Obj now has 3 values
# Out: 
# Out:  Obj has 3 values
# Out: Obj now has 4 values
# Out: Obj final result:
# Out: {'0': 0, '1': 1, '2': 2, '3': 3} 

Совместное использование состояния между процессами

Код, выполняемый в разных процессах, по умолчанию не разделяет одни и те же данные. Однако multiprocessing модуль содержит примитивы , чтобы помочь стоимость акций через несколько процессов.

 import multiprocessing

plain_num = 0
shared_num = multiprocessing.Value('d', 0)
lock = multiprocessing.Lock()

def increment():
    global plain_num
    with lock:
        # ordinary variable modifications are not visible across processes
        plain_num += 1
        # multiprocessing.Value modifications are
        shared_num.value += 1

ps = [multiprocessing.Process(target=increment) for n in range(4)]
for p in ps:
    p.start()
for p in ps:
    p.join()

print("plain_num is %d, shared_num is %d" % (plain_num, shared_num.value))

# Out: plain_num is 0, shared_num is 4 

Синтаксис

Параметры

Примечания

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.