【问题标题】:why single thread is faster than multithread in Ubuntu using pthread?为什么在使用 pthread 的 Ubuntu 中单线程比多线程快?
【发布时间】:2015-01-12 10:46:15
【问题描述】:

XUbuntu 14.04,2 个处理器。

多线程耗时0.8s,单线程耗时0.4s。

如果定义了MULTI_THREAD,那么程序将在单线程中运行。否则就是多线程程序

怎么了?

 ----------------code------------------------------

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

    #define MULTI_THREAD
    #define NUM             10000
    #define SEM_M           10
    int arr[NUM];
    FILE *f;

        typedef struct _SemData{
            sem_t           sem_full;
            sem_t           sem_empty;
        }SemData;

        void InitSemData(SemData *sd){
            sem_init(&sd->sem_full,0,0);
            sem_init(&sd->sem_empty,0,SEM_M);
        }

        void DestroySemData(SemData *sd){

                sem_destroy(&sd->sem_full);
                sem_destroy(&sd->sem_empty);
            }

            void *Produce(void* data){
            #ifdef MULTI_THREAD
                SemData* psd=(SemData*)data;
            #endif
                int i;
                for(i=0;i<NUM;++i){
            #ifdef MULTI_THREAD
                    sem_wait(&psd->sem_empty);
            #endif
                        arr[i]=i;
                        fprintf(f,"produce:%d\n",arr[i]);
            #ifdef MULTI_THREAD
                    sem_post(&psd->sem_full);
            #endif
                }
            }

        void *Custom(void* data){
        #ifdef MULTI_THREAD
            SemData* psd=(SemData*)data;
        #endif
            int i,j;
            for(i=0;i<NUM;++i){
        #ifdef MULTI_THREAD
                sem_wait(&psd->sem_full);
        #endif
                    int tmp=0;
                    for(j=0;j<NUM;++j){
                        tmp+=arr[i];
                    }
                    arr[i]=tmp;
                    fprintf(f,"Custom:%d\n",arr[i]);
        #ifdef MULTI_THREAD
                sem_post(&psd->sem_empty);
        #endif
            }
        }

        void main(){
            f=fopen("b.txt","w");
            clock_t start=clock();
        #ifdef MULTI_THREAD
            SemData sd;
            InitSemData(&sd);

            pthread_t th0,th1;
            pthread_create(&th0,NULL,Produce,(void*)&sd);
            pthread_create(&th1,NULL,Custom,(void*)&sd);

            pthread_join(th0,NULL);
            pthread_join(th1,NULL);

            DestroySemData(&sd);
        #else
            Produce(NULL);
            Custom(NULL);
        #endif
            printf("TotalTime:%fs\n",((float)(clock()-start))/CLOCKS_PER_SEC);
            fclose(f);
        }

【问题讨论】:

  • 如果定义了多线程,那么它会运行多线程吗?
  • 锁不是免费的。锁甚至都不便宜。根据您的程序,增加的开销可能不如单线程版本。
  • 看看有多少代码被执行只是为了复制一个值,然后复制+添加。换句话说,MULTI_THREAD 定义的操作很可能比它们的对应物慢约 20,这对我来说并不奇怪。

标签: c++ c linux multithreading


【解决方案1】:

一般来说,并行化会带来额外的成本。您必须进行通信以分发和收集数据。此外,同步可能非常昂贵。

【讨论】:

  • 你的意思是每个线程的工作成本不够用多线程吗?这些工作成本与多线程增加的开销一样多
  • 是的,有点,这取决于实际的硬件和问题的大小。很难做出笼统的陈述。
【解决方案2】:

你的单线程代码是这样工作的:

  1. 产生所有的数字
  2. 消耗所有数字

多线程代码是这样工作的:

Producer                             Consumer
--------                             --------
Produce one number                   Wait for a number to be produced
Wait for a number to be consumed     Consume one number
Produce one number                   Wait for a number to be produced
Wait for a number to be consumed     Consume one number
Produce one number                   Wait for a number to be produced
Wait for a number to be consumed     Consume one number
...

如您所见,实际上一次只有一个线程在做任何事情。
如果没有信号和上下文切换的开销,这将花费与单线程代码大致相同的时间,但由于信号和上下文切换非常昂贵,因此速度要慢得多。

即使你重写你的多线程代码以首先产生所有的数字然后消费它们,它会更慢,因为这将与单线程代码完全相同加上信号和上下文切换。

【讨论】:

  • 我分配了 10 个 sem(sem_init(&sd->sem_empty,0,10))。我认为它会像一个可以包含 10 个元素的循环队列一样工作。生产者使用前,消费者使用后。但是......你是对的,所以谢谢你!
  • 你的答案太明显了!^_^
  • @Shuaizi 谢谢,但我不确定我的描述是否正确。至少它有帮助......
【解决方案3】:

您正在测试的算法不需要在多个线程中被破坏以提高效率:您必须考虑到创建新线程总是存在开销(即分配一些资源、等待同步等)。 您必须评估新线程创建开销和单线程复杂性之间的权衡。

【讨论】:

    猜你喜欢
    • 2013-11-22
    • 1970-01-01
    • 2014-07-21
    • 2017-12-26
    • 2021-12-14
    • 2015-07-09
    • 2016-08-09
    • 1970-01-01
    • 2018-08-24
    相关资源
    最近更新 更多