34. Действительно ли многопоточность быстрее однопоточности?

Python
34. Действительно ли многопоточность быстрее однопоточности?

@Автор: Рансен

На самом деле, еще одна очень важная тема многопоточности в Python называетсяGIL(Global Interpreter Lock, то есть глобальная блокировка интерпретатора).

Многопоточность не обязательно быстрее, чем однопоточность

В Python многозадачность может быть достигнута за счет многопроцессорности, многопоточности и многозадачности. Обязательно ли многопоточность быстрее, чем однопоточность?

Ниже я использую фрагмент кода, чтобы доказать свою точку зрения.

'''
@Author: Runsen
@微信公众号: Python之王
@博客: https://blog.csdn.net/weixin_44510615
@Date: 2020/6/4
'''

import threading, time
def my_counter():
    i = 0
    for _ in range(100000000):
        i = i+1
    return True

def main1():
    start_time = time.time()
    for tid in range(2):
        t = threading.Thread(target=my_counter)
        t.start()
        t.join()  # 第一次循环的时候join方法引起主线程阻塞,但第二个线程并没有启动,所以两个线程是顺序执行的

    print("单线程顺序执行total_time: {}".format(time.time() - start_time))

def main2():
    thread_ary = {}
    start_time = time.time()
    for tid in range(2):
        t = threading.Thread(target=my_counter)
        t.start()
        thread_ary[tid] = t

    for i in range(2):
        thread_ary[i].join()  # 两个线程均已启动,所以两个线程是并发的

    print("多线程执行total_time: {}".format(time.time() - start_time))

if __name__ == "__main__":
    main1()
    main2()

результат операции

单线程顺序执行total_time: 17.754502773284912
多线程执行total_time: 20.01178550720215

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

В это время я сомневаюсь: моя машина вышла из строя? На самом деле это не так, по сути Python thread недействителен, не играл в параллельные вычисления.

Потоки Python инкапсулируют базовые потоки операционной системы.Pthread(полное имяPOSIX Thread), в то время как в Windows этоWindows Thread. Кроме того, потоки Python также полностью управляются операционной системой, например, координируя время выполнения, управляя ресурсами памяти, управляя прерываниями и так далее.

GIL не является функцией Python

Концепция GIL объясняется простым предложением, то естьОдин интерпретатор CPython может одновременно выполнять только один байт-код, независимо от количества потоков.. Что следует отметить в отношении этого определения:

Первое, что должно быть ясно, это то, чтоGIL не является функцией Python, концепция, появившаяся при реализации синтаксического анализатора Python (CPython).

C++ представляет собой набор стандартов языка (синтаксиса), но может быть скомпилирован в исполняемый код с помощью различных компиляторов. Известные компиляторы, такие как GCC, INTEL C++, Visual C++ и т. д.

То же самое верно и для Python: один и тот же фрагмент кода может выполняться в разных средах выполнения Python, таких как CPython, PyPy и Psyco.

Другие интерпретаторы Python не обязательно имеют GIL.. Например, Jython (JVM) и IronPython (CLR) не имеют GIL, а CPython, PyPy имеют GIL;

Потому что CPython является средой выполнения Python по умолчанию в большинстве сред. Поэтому в представлении многих людей CPython — это Python, и считается само собой разумеющимся, что GIL относят к недостаткам языка Python. Итак, давайте проясним здесь:GIL не является особенностью Python, Python может быть полностью независимым от GIL.

GIL по сути является мьютексом

Суть GIL - блокировка взаимного исключения. Поскольку это блокировка взаимного исключения, суть всех блокировок взаимного исключения одинакова. Все они превращают параллельную операцию в последовательную, чтобы контролировать, что общие данные могут быть изменены только одним задача одновременно. , тем самым обеспечивая безопасность данных.

Одно можно сказать наверняка: для защиты безопасности разных данных вы должны добавлять разные блокировки.

GIL работает: например, на картинке ниже показан рабочий пример GIL в программах на Python. Который, по очереди выполняя поток 1, 2, 3, в начале выполнения каждого потока будет блокировать GIL, чтобы предотвратить выполнение других потоков; то же самое, каждый поток после некоторого времени выполнения освобождает GIL, чтобы разрешить другому потоку начать использование ресурсов.

вычислительно интенсивный

Задачи с интенсивными вычислениями характеризуются большим количеством вычислений, потребляющих ресурсы ЦП.

Давайте начнем с простого примера с интенсивными вычислениями:

'''
@Author: Runsen
@微信公众号: Python之王
@博客: https://blog.csdn.net/weixin_44510615
@Date: 2020/6/4
'''
import time
COUNT = 50_000_000

def count_down():
   global COUNT
   while COUNT > 0:
       COUNT -= 1

s = time.perf_counter()
count_down()
c = time.perf_counter() - s
print('time taken in seconds - >:', c)

time taken in seconds - >: 9.2957003

Это один поток, время 9 секунд, давайте используем два потока, чтобы увидеть результат:

'''
@Author: Runsen
@微信公众号: Python之王
@博客: https://blog.csdn.net/weixin_44510615
@Date: 2020/6/4
'''
import time
from threading import Thread

COUNT = 50_000_000

def count_down():
   global COUNT
   while COUNT > 0:
       COUNT -= 1

s = time.perf_counter()
t1 = Thread(target=count_down)
t2 = Thread(target=count_down)
t1.start()
t2.start()
t1.join()
t2.join()
c = time.perf_counter() - s
print('time taken in seconds - >:', c)

time taken in seconds - >: 17.110625

Основная операция нашей программы это расчет, ЦП не ждет, а после перехода на многопоточность, после добавления потоков, частое переключение между потоками увеличивает накладные расходы, а время конечно увеличится.

Другой тип — интенсивный ввод-вывод.Все задачи, связанные с сетевым и дисковым вводом-выводом, являются задачами, интенсивными вводом-выводом.Этот тип задач характеризуется очень небольшим потреблением ЦП, и большую часть времени задача ожидает завершения операции ввода-вывода (поскольку Скорость ввода-вывода намного ниже, чем скорость процессора и памяти). Для задач с интенсивным вводом-выводом чем больше задач, тем выше эффективность ЦП, но есть предел. Наиболее распространенными задачами являются задачи с интенсивным вводом-выводом, такие как веб-приложения.

Резюме: Для IO-интенсивной работы (Python Crawler) многопоточность может значительно улучшить эффективность кода. Для CPU-интенсивных вычислений (анализ данных Python, машинное обучение, глубокое обучение), многопотока может быть немного менее эффективной, чем однопоточная. Следовательно, в поле данных нет такой вещи, как многопоточь для повышения эффективности, но только путем обновления процессора в GPU и TPU для улучшения вычислительной мощности.

Ссылаться на:Колонка Python «Время гиков»~

Эта статья была включена в GitHub,Портал~, а также полноценные тестовые сайты для интервью с крупными производителями Добро пожаловать в Star.