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

Введение

Примеры

  • 2

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

    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 
  • 0

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

    Используйте 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 
  • 0

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

    Используйте 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 
  • 0

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

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

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

     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} 
  • 0

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

    Код, выполняемый в разных процессах, по умолчанию не разделяет одни и те же данные. Однако 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 

Синтаксис

Параметры

Примечания