Почему запуск 2 процессов на 2 ядрах медленнее, чем на одном ядре?

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

Вот моя программа на Python для подсчета:

import time

start = time.time()
j = 0

for i in range(0, 80000000):
    j += i

elapsed = time.time() - start
print("\nElapsed: %f" % elapsed)

Сама по себе эта программа завершается примерно за 7 секунд. Если я запускаю эту программу дважды одновременно на одном и том же ядре ЦП:

$ taskset --cpu-list 0 time python3 cpu-bound.py & taskset --cpu-list 0 time python3 cpu-bound.py &

Elapsed: 15.553317
7.77user 0.01system 0:15.59elapsed 49%CPU (0avgtext+0avgdata 8924maxresident)k
0inputs+0outputs (0major+942minor)pagefaults 0swaps

Elapsed: 15.840124
8.10user 0.00system 0:15.90elapsed 50%CPU (0avgtext+0avgdata 9060maxresident)k
0inputs+0outputs (0major+946minor)pagefaults 0swaps

Я получаю 14-15 секунд, что ожидается, поскольку они работают на одном и том же ЦП, поэтому один должен быть приостановлен для запуска другого и т. д. Однако запуск двух процессов на разных ядрах ЦП:

$ taskset --cpu-list 0 time python3 cpu-bound.py & taskset --cpu-list 1 time python3 cpu-bound.py &

Elapsed: 17.081092
17.10user 0.00system 0:17.12elapsed 99%CPU (0avgtext+0avgdata 8848maxresident)k
0inputs+0outputs (0major+943minor)pagefaults 0swaps

Elapsed: 17.094898
17.10user 0.00system 0:17.14elapsed 99%CPU (0avgtext+0avgdata 8948maxresident)k
0inputs+0outputs (0major+944minor)pagefaults 0swaps

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

Тем не менее, я вижу 15-17 секунд выполнения каждого процесса.

Может ли кто-нибудь пролить свет на это поведение? Спасибо!

Обновлять: Ниже я опишу среды, в которых я пытался это запустить.

Сначала я запустил это в контейнере Docker на Mac M1 с 4 ядрами. CPU 0 и 1 — это первое и второе ядро ​​соответственно. Затем я снова запустил виртуальную машину t3.medium на AWS с двумя виртуальными ЦП и получил аналогичные результаты.

Обновлять: Я также получил аналогичные результаты в PHP, а также статический пул php-fpm с 1 воркером (для последовательного запуска), с 2 воркерами с привязкой к ЦП (для параллельной работы на одном ядре) и с 2 воркерами без привязки (параллельный на двух ядрах). Я наблюдал похожее поведение — параллельный запуск на отдельных ядрах далеко не так быстр, как исходный одиночный запуск.

Затем я решил попробовать аналогичную программу на C, и результаты были совсем другими и очень соответствовали тому, что я ожидал в первую очередь:

#include <stdio.h>
#include <time.h>
    
int main() {
    time_t t;
    double elapsed;
    int i, j = 0;
    t = time(NULL);
    
    for (i = 0; i <= 2000000000; i++) {
        j += i;
    }
    
    t = time(NULL) - t;
    elapsed = ((double) t);
    printf("Elapsed: %f\n", elapsed);
    return 0;
}

Один запуск длился около 6 секунд (время_t округляется до секунд):

$ ./a.out 
Elapsed: 6.000000

Два запуска на одном ядре ЦП дали:

$ taskset --cpu-list 0 ./a.out & taskset --cpu-list 0 ./a.out &
Elapsed: 12.00
Elapsed: 12.00

Два прогона на отдельных ядрах ЦП дали:

$ taskset --cpu-list 0 ./a.out & taskset --cpu-list 1 ./a.out &
Elapsed: 6.00
Elapsed: 6.00

Такое поведение больше соответствует тому, что я ожидал изначально, но почему оно так сильно отличается для Python и PHP?

1 ответ
1

Такое поведение больше соответствует тому, что я ожидал изначально, но почему оно так сильно отличается для Python и PHP?

И Python, и PHP являются интерпретируемыми языками высокого уровня. Вы не можете точно знать, что интерпретатор делает с вашим кодом.

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

Это одна из основных причин использования C.

Сначала я запустил это в контейнере Docker на Mac M1 с 4 ядрами. CPU 0 и 1 — это первое и второе ядро ​​соответственно. Затем я снова запустил виртуальную машину t3.medium на AWS с двумя виртуальными ЦП и получил аналогичные результаты.

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

Массимо

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *