Comparaison équitable de fork() Vs Thread

J'ai eu une discussion sur le coût relatif de fork() Vs thread() pour la parallélisation d'une tâche.

Nous comprendre les différences fondamentales entre les processus Vs Fil

Fil:

  • Facile la communication entre les threads
  • Rapide changement de contexte.

Processus:

  • La tolérance aux pannes.
  • Communiquer avec le parent qui n'est pas un problème d'ouvrir un pipe)
  • La Communication avec d'autres processus enfants dur

Mais nous étions en désaccord sur le coût de démarrage de processus de Vs threads.

Afin de tester les théories que j'ai écrit le code suivant. Ma question: Est-ce un test valide de mesurer le coût de démarrage ou il me manque quelque chose. Aussi je serais intéressée de savoir comment chaque test exécute sur différentes plates-formes.

fork.cpp

#include <boost/lexical_cast.hpp>
#include <vector>
#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

extern "C" int threadStart(void* threadData)
{
    return 0;
}

int main(int argc,char* argv[])
{
    int threadCount =  boost::lexical_cast<int>(argv[1]);

    std::vector<pid_t>   data(threadCount);
    clock_t                 start   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        data[loop]  = fork();
        if (data[looo] == -1)
        {
            std::cout << "Abort\n";
            exit(1);
        }
        if (data[loop] == 0)
        {
            exit(threadStart(NULL));
        }
    }
    clock_t                 middle   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        int   result;
        waitpid(data[loop], &result, 0);
    }
    clock_t                 end   = clock();

   std::cout << threadCount << "\t" << middle - start << "\t" << end - middle << "\t"<< end - start << "\n";
}

Thread.cpp

#include <boost/lexical_cast.hpp>
#include <vector>
#include <iostream>
#include <pthread.h>
#include <time.h>


extern "C" void* threadStart(void* threadData)
{
    return NULL;
}   

int main(int argc,char* argv[])
{
    int threadCount =  boost::lexical_cast<int>(argv[1]);

    std::vector<pthread_t>   data(threadCount);

    clock_t                 start   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {
        if (pthread_create(&data[loop], NULL, threadStart, NULL) != 0)
        {
            std::cout << "Abort\n";
            exit(1);
        }
    }   
    clock_t                 middle   = clock();
    for(int loop=0;loop < threadCount;++loop)
    {   
        void*   result;
        pthread_join(data[loop], &result);
    }
    clock_t                 end   = clock();

   std::cout << threadCount << "\t" << middle - start << "\t" << end - middle << "\t"<< end - start << "\n";

}

J'attends de Windows pour faire de pire dans le processus de création.

Mais je m'attends moderne systèmes Unix d'avoir assez de lumière fourchette de coût et d'être au moins comparable à enfiler. Sur les anciens systèmes de type Unix (avant le fork() a été implémenté à l'aide de la copie sur écriture de pages) que ce serait encore pire.

De toute façon Mon calendrier résultats sont les suivants:

> uname -a
Darwin Alpha.local 10.4.0 Darwin Kernel Version 10.4.0: Fri Apr 23 18:28:53 PDT 2010; root:xnu-1504.7.4~1/RELEASE_I386 i386
> gcc --version | grep GCC
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659)
> g++ thread.cpp -o thread -I~/include
> g++ fork.cpp -o fork -I~/include
> foreach a ( 1 2 3 4 5 6 7 8 9 10 12 15 20 30 40 50 60 70 80 90 100 )
foreach? ./thread ${a} >> A
foreach? end
> foreach a ( 1 2 3 4 5 6 7 8 9 10 12 15 20 30 40 50 60 70 80 90 100 )
foreach? ./fork ${a}  >> A
foreach? end
vi A 
Thread:                             Fork:
C   Start   Wait    Total           C   Start   Wait    Total
==============================================================
1    26     145     171             1   160     37      197
2    44     198     242             2   290     37      327
3    62     234     296             3   413     41      454
4    77     275     352             4   499     59      558
5    91     107   10808             5   599     57      656
6    99     332     431             6   665     52      717
7   130     388     518             7   741     69      810
8   204     468     672             8   833     56      889
9   164     469     633             9  1067     76     1143
10   165     450     615            10  1147     64     1211
12   343     585     928            12  1213     71     1284
15   232     647     879            15  1360    203     1563
20   319     921    1240            20  2161     96     2257
30   461    1243    1704            30  3005    129     3134
40   559    1487    2046            40  4466    166     4632
50   686    1912    2598            50  4591    292     4883
60   827    2208    3035            60  5234    317     5551
70   973    2885    3858            70  7003    416     7419
80  3545    2738    6283            80  7735    293     8028
90  1392    3497    4889            90  7869    463     8332
100 3917    4180    8097            100 8974    436     9410

Edit:

Faire un 1000 enfants ont provoqué la fourche version à l'échec.

Donc j'ai réduit les enfants de compter. Mais faire un seul test semble aussi injuste donc, ici, est une plage de valeurs.

  • Jetez un oeil à cette réponse quant à la façon dont les threads et les processus sont différents en ce qui concerne les performances: stackoverflow.com/questions/3609469/...
  • Difficile de voir comment il serait un test significatif. Vous n'avez rien fait pour mesurer le coût de la mise en place de la communication que de la fourche exige.
  • le choix entre la fourche et le fil est (presque?) jamais conduit par les performances. La fonctionnalité est totalement différent; le pilote est "qu'essayez-vous de le faire"
  • Passant: Juste point de. Malheureusement, cela devient très spécifique des tâches. Toutes les suggestions. J'essayais juste de montrer que le coût de démarrage n'est pas un facteur dans le choix de savoir si l'utilisation de threads/processus.
  • Menuisier: Celles-ci sont toutes de bonnes raisons de penser au moment de choisir météo pour l'utilisation de threads/processus. Je suis en train d'essayer (pas réussi encore) que le coût de démarrage n'est pas un facteur qui devraient influencer votre décision (la différence est mineure et les autres facteurs sont plus importants).
  • Je suis d'accord avec cela.
  • Gardez à l'esprit que la copie sur écriture des pages n'est pas faire de la surcharge en aller. C'est juste reporté jusqu'à ce que ces pages sont accessibles. Aussi, même avec de la VACHE pages, le coût de démarrage d'un processus est encore plus élevé que pour un thread (mais généralement pas trop donc)
  • VACHE permettra d'éviter toutes les pages de code et de tous les lire uniquement les données des pages du besoin d'être copié. Ainsi, seules les pages avec l'écriture de données doivent être copiées. Aussi comme @Hans Passant: souligné il n'y a pas de comminication canal configuré pour transmettre des informations à la maison mère (peut-être supplémentaire de la copie peut être éviter en utilisant la mémoire partagée ici (c'est une question))
  • vrai, bien sûr. Pas sûr de ce que je pensais. :p

InformationsquelleAutor Martin York | 2010-10-14