Делает ли Linux разделение времени на процессы или потоки - PullRequest
2 голосов
/ 19 февраля 2010

Профессор однажды сказал нам в классе, что Windows, Linux, OS X и UNIX масштабируются в потоках, а не в процессах, поэтому потоки, скорее всего, принесут пользу вашему приложению даже на одном процессоре, поскольку ваше приложение будет получать больше времени на процессоре.

Я попытался с помощью следующего кода на моей машине (которая имеет только один процессор).

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_t xs[10];

void *nop(void *ptr) {
    unsigned long n = 1UL << 30UL;
    while(n--);
    return NULL;
}

void test_one() {

    size_t len = (sizeof xs) / (sizeof *xs);
    while(len--)
        if(pthread_create(xs+len, NULL, nop, NULL))
            exit(EXIT_FAILURE);

    len = (sizeof xs) / (sizeof *xs);
    while(len--)
        if(pthread_join(xs[len], NULL))
            exit(EXIT_FAILURE);

}

void test_two() {

    size_t len = (sizeof xs) / (sizeof *xs);
    while(len--) nop(NULL);

}

int main(int argc, char *argv[]) {

    test_one();
//  test_two();
    printf("done\n");
    return 0;
}

Оба теста были идентичны по скорости.

real    0m49.783s
user    0m48.023s
sys     0m0.224s

real    0m49.792s
user    0m49.275s
sys     0m0.192s

Это я думаю: "Ух ты, нить отстой".Но повторение теста на университетском сервере с четырьмя процессорами, близкими к четырехкратному, увеличило скорость.

real    0m7.800s
user    0m30.170s
sys     0m0.006s

real    0m30.190s
user    0m30.165s
sys     0m0.004s

Я что-то пропускаю при интерпретации результатов с моего домашнего компьютера?

Ответы [ 3 ]

24 голосов
/ 19 февраля 2010

Чтобы понять в недрах задач / потоков ... давайте посмотрим на этот игрушечный код ядра ...

struct regs{
  int eax, ebx, ecx, edx, es, ds, gs, fs, cs, ip, flags;
  struct tss *task_sel;
}

struct thread{
    struct regs *regs;
    int parent_id;
    struct thread *next;
}
struct task{
   struct regs *regs;
   int *phys_mem_begin;
   int *phys_mem_end;
   int *filehandles;
   int priority;
   int *num_threads;
   int quantum;
   int duration;
   int start_time, end_time;
   int parent_id;
   struct thread *task_thread;
     /* ... */
   struct task *next;
}

Представьте, что ядро ​​выделяет память для этой структуры task, которая является связанным списком, посмотрите внимательно на поле quantum, которое является временным интервалом времени процессора на основе поля priority. Всегда будет задание с идентификатором 0, которое никогда не спит, просто бездействует, возможно, выдает nops (No OPerationS) ... планировщик вращается вокруг тошноты до бесконечности (то есть когда питание отключается), если quantum поле определяет, что задача выполняется в течение 20 мс, устанавливает значения start_time и end_time + 20 мс, когда этот end_time активен, ядро ​​сохраняет состояние регистров процессора в указатель regs. Переходит к следующей задаче в цепочке, загружает регистры процессора из указателя в regs и переходит в инструкцию, устанавливает квантовую и временную длительности, когда длительность достигает нуля, переходит к следующей ... эффективно переключение ... это то, что создает иллюзию одновременной работы на одном процессоре.

Теперь посмотрите на структуру thread, которая является связанным списком потоков ... внутри этой структуры task. Ядро выделяет потоки для указанной задачи, устанавливает состояния процессора для этого потока и переходит в потоки ... теперь ядро ​​должно управлять потоками, а также самими задачами ... опять переключение контекста между задачей и потоком ...

Перейдите к многопроцессорному процессору, ядро ​​было бы настроено на масштабируемость, и что бы делал планировщик, загрузите один task на один процессор, загрузите другой на другой процессор (двухъядерный), и оба перейдите туда, куда указывает указатель инструкции ... теперь ядро ​​действительно выполняет обе задачи одновременно на обоих процессорах. Масштабирование до 4-х, то же самое, дополнительные задачи, загруженные на каждый процессор, масштабирование снова, до n-way ... вы получаете дрейф.

Как вы можете видеть, как потоки не будут восприниматься как масштабируемые, так как ядро ​​откровенно выполняет гигантскую задачу по отслеживанию того, что выполняет процессор, и, кроме того, какая задача выполняется, какие потоки , что в основном объясняет, почему я думаю, что потоки не являются точно масштабируемыми ... Потоки потребляют много ресурсов ...

Если вы действительно хотите увидеть, что происходит, взгляните на исходный код для Linux, особенно в планировщике. Не зацикливайтесь, забудьте о выпусках ядра 2.6.x, посмотрите доисторическую версию 0.99, планировщик будет проще для понимания и легче для чтения, конечно, он немного устарел, но стоит посмотреть, это поможет вам понять почему и, надеюсь, мой ответ также: почему потоки не масштабируются ... и показывает, как игрушечная операционная система использует временное разделение на основе процессов. Я стремился не вдаваться в технические аспекты современных процессоров, которые могут сделать больше, чем я описал ...

Надеюсь, это поможет.

4 голосов
/ 19 февраля 2010

Профессор однажды сказал нам в классе, что Windows, Linux, OS X и UNIX масштабируются в потоках, а не в процессах, поэтому потоки, скорее всего, принесут пользу вашему приложению даже на одном процессоре, поскольку ваше приложение будет получать больше времени на процессоре.

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

Это я думаю: "Ух ты, нить отстой". Но повторение теста на университетском сервере с четырьмя процессорами, близкими к четырехкратной скорости.

Это потому, что с четырьмя потоками он может использовать все четыре процессора.

1 голос
/ 19 февраля 2010

Я не совсем уверен, что вы спрашиваете, но вот ответ, который может помочь.

В Linux процессы и потоки практически одинаковы. Планировщик понимает вещи, называемые «задачами», которые не заботятся о том, разделяют ли они адресное пространство или нет. Поделиться или не делиться вещами действительно зависит от того, как они были созданы.

Вопрос о том, использовать ли потоки или процессы, является ключевым решением при разработке, и его не следует воспринимать легкомысленно, но производительность планировщика, вероятно, не является фактором (конечно, такие вещи, как требования IPC, сильно изменят дизайн)

...