Почему в этом примере неэффективно распределяются несколько потоков?

#python #multithreading

#python #многопоточность

Вопрос:

У меня есть тест, почему я могу запустить, чтобы получить около 5 секунд 100% времени загрузки процессора на одном из моих ядер.

Это сценарий

 from threading import Thread
from time import time, sleep

def test0():
    start = time()
    a = 0
    for _ in range(int(1e8)):
        a  = 1
    print(time() - start)
 

Это трассировка (системный монитор Ubuntu 20.04 с временными ячейками 1 секунды)

введите описание изображения здесь

Прохладный. Это имеет смысл. Один из моих процессоров работает на 100% около 5 секунд.

Теперь, что произойдет, если я попытаюсь запустить 4 потока, каждый из которых выполняет одно и то же? С моими текущими знаниями я бы подумал, что они должны быть распределены по времени на одном ядре, и все это должно занять около 20 секунд. Вот сценарий

 def print_after_work(msg):
    a = 0
    for _ in range(int(1e8)):
        a  = 1
    print(msg)
    

def test1():
    threads = []
    for i in range(4):
        threads.append(threading.Thread(target=print_after_work, args=[i 1]))
    start = time()
    for thread in threads:
        thread.start()
        sleep(0.2)
    for thread in threads:
        thread.join()
    print(time() - start)
 

И вот трассировка:

введите описание изображения здесь

Итак, у нас есть 4 процессора, работающих с пропускной способностью около 25%.

Вопросы:

  1. Таким threading образом, модуль Python может перемещать потоки в разные ядра, отличные от основного процесса?
  2. Если да, то почему для этого используется только 25% каждого ядра, что занимает в 4 раза больше времени?

Комментарии:

1.Прочитайте о python GIL wiki.python.org/moin/GlobalInterpreterLock opensource.com/article/17/4/grok-gil

2. Вкратце — потоки Python не используют несколько ядер, потому что все потоки совместно используют общие данные внутри.

3. @AvihayTsayeg имеет смысл теперь, когда сумма по всем ядрам равна 100%. Но все еще не уверен в ответе на мой первый вопрос.

4. @TonySuffolk66 тогда почему в моем примере работает несколько ядер?

5. @AlexanderSoare O / S Привязка времени — сам процесс Python почти наверняка переключается между ядрами на каждом временном отрезке. Нет никакой гарантии, что процесс будет постоянно привязан к одному и тому же ядру. Ваш график не показывает степень детализации этого временного интервала O / S. Итак, то, что вы видите, — это совокупность по времени 4 ядер.

Ответ №1:

Потоки Python не используют несколько ядер, потому что все потоки совместно используют общие данные внутри: Python GIL.

То, что вы видите на своем графике, — это совокупный эффект привязки времени ОС — сам процесс Python почти наверняка обменивается между ядрами на каждом временном отрезке. Нет никакой гарантии, что процесс будет постоянно привязан к одному и тому же ядру. Однако ваш график не показывает степень детализации этого временного интервала O / S. Итак, то, что вы видите, — это совокупность во времени 4 ядер, что означает, что вы получаете 25% от каждого процессора или эквивалент 100% от одного процессора — как вы ожидаете увидеть в многопоточности Python, где все потоки привязаны к одному и тому же процессору, когда все потоки подключены к одному процессору.сам процесс запланирован.