zoukankan      html  css  js  c++  java
  • Linux多线程实践(7) --多线程排序对比

    屏障

    int pthread_barrier_init(pthread_barrier_t *restrict barrier,
                             const pthread_barrierattr_t *restrict attr,
                             unsigned count);
    int pthread_barrier_destroy(pthread_barrier_t *barrier);
    
    int pthread_barrier_wait(pthread_barrier_t *barrier);

      屏障允许任意数量的线程等待, 直到所有的线程完成处理工作, 而线程不需要退出, 所有线程达到屏障之后可以接着工作.

      init:在初始化屏障时, 可以使用第三个参数count指定, 在允许所有线程继续运行之前, 必须到达屏障的线程数目.

      wait:可以使用pthread_barrier_wait函数来表明, 线程已经完成工作, 准备等所有其他线程赶上来;

        调用wait的线程在屏障计数未满足条件时, 会进入休眠状态. 如果该线程是最后一个调用wait的线程, 就满足了屏障计数, 所有的线程都被唤醒.

      对于一个任意线程, pthread_barrier_wait函数返回了PTHREAD_BARRIER_SERIAL_THREAD. 剩下的线程看到的返回值是0. 这使得一个线程可以作为主线程, 他可以工作在其他所有线程已完成的工作结果上.

     

    单线程与多线程排序

    单线程排序

    bool compare(long a, long b)
    {
        return a < b;
    }
    
    #define NUMNUM 8000000L
    long int nums[NUMNUM];  //待排序数组(约32M)
    
    int main()
    {
        srandom(time(NULL));
        for (unsigned long i = 0; i < NUMNUM; i++)
            nums[i] = random();
    
        struct timeval  start, end;
        //计时开始
        gettimeofday(&start,NULL);
        sort(nums,nums+NUMNUM,compare); //单线程排序,快速排序
        gettimeofday(&end,NULL);
    
        //计算用时
        long long startusec = start.tv_sec * 1000000 + start.tv_usec;
        long long endusec = end.tv_sec * 1000000 + end.tv_usec;
        double elapsed = (double)(endusec - startusec) / 1000000.0;
        printf("sort took %.4f seconds
    ", elapsed);
    
        //将排序后的结果写入文件, 以便查看是否已经排好序
        FILE *fp = fopen("save.txt", "w+");
        for (unsigned long i = 0; i < NUMNUM; i++)
            fprintf(fp, "%ld ", nums[i]);
    }

    三次排序用时如下:

      sort took 3.2435 seconds

      sort took 3.2221 seconds

      sort took 3.2134 seconds

    (附-主机配置: 双核四线程(Intel(R) Core(TM) i3-2350M CPU @ 2.30GHz))

     

    多线程排序(使用屏障同步)

    #define NTHR   8                /* 线程数 */
    #define NUMNUM 8000000L         /* 待排序数 */
    #define TNUM   (NUMNUM/NTHR)    /* 每个线程分配到的需要排序的数 */
    long nums[NUMNUM];
    long snums[NUMNUM];
    pthread_barrier_t b;    //屏障
    
    bool compare(long a, long b)
    {
        return a < b;
    }
    //排序线程
    //对nums数组的从idx~idx+TNUM部分进行快速排序
    void *workThread(void *arg)
    {
        long    idx = (long)arg;
    
        sort(&nums[idx],&nums[idx+TNUM],compare);
        pthread_barrier_wait(&b);
    
        pthread_exit(NULL);
    }
    
    //对已经排好序数组nums的NTHR部分进行合并
    void merge()
    {
        long idx[NTHR];  //idx保存数组nums的NTHR部分的起始位置
        for (long i = 0; i < NTHR; i++)
            idx[i] = i * TNUM;
    
        for (long sidx = 0; sidx < NUMNUM; sidx++)
        {
            long minidx;
            long num = LONG_MAX;
    
            //从NTHR部分的数组中查找出最小的一个, 将其index保存到idx[minidx]中
            for (long i = 0; i < NTHR; i++)
            {
                //idx[i] < (i+1)*TNUM 确保是在一个部分之中,
                //不会产生两个部分相互比较的情况
                if ((idx[i] < (i+1)*TNUM) && (nums[idx[i]] < num))
                {
                    num = nums[idx[i]];
                    minidx = i;
                }
            }
    
            snums[sidx] = nums[idx[minidx]];
            idx[minidx]++;
        }
    }
    
    int main()
    {
        srandom(time(NULL));
        for (unsigned long i = 0; i < NUMNUM; i++)
            nums[i] = random();
    
        //创建NTHR个线程分别对数组相邻的NTHR部分进行排序
        struct timeval  start, end;
        pthread_t       tid;
        gettimeofday(&start, NULL);
        pthread_barrier_init(&b, NULL, NTHR+1);
        for (unsigned long i = 0; i < NTHR; i++)
            pthread_create(&tid, NULL,workThread, (void *)(i * TNUM));
        pthread_barrier_wait(&b);
        merge();
        gettimeofday(&end, NULL);
    
        //计算用时
        long long startusec = start.tv_sec * 1000000 + start.tv_usec;
        long long endusec = end.tv_sec * 1000000 + end.tv_usec;
        double elapsed = (double)(endusec - startusec) / 1000000.0;
        printf("sort took %.4f seconds
    ", elapsed);
    
        //将排序后的结果写入文件, 以便查看是否已经排好序
        FILE *fp = fopen("save.txt", "w+");
        for (unsigned long i = 0; i < NUMNUM; i++)
            fprintf(fp, "%ld ", snums[i]);
    }

    八线程排序:

      sort took 1.5556 seconds

      sort took 1.5676 seconds

      sort took 1.5719 seconds 

    四线程排序:

      sort took 1.4132 seconds

      sort took 1.4315 seconds

      sort took 1.4738 seconds

    二线程排序:

      sort took 2.0581 seconds

      sort took 2.2358 seconds

      sort took 1.7775 seconds

    (附-主机配置: 双核四线程(Intel(R) Core(TM) i3-2350M CPU @ 2.30GHz))

     

    总结: 可以看到尽管在分别进行排序之后还要有合并(merge)这一步,多线程排序(计算密集型任务)还是要优于单线程排序(在CPU为多核的情况下),而且在CPU为四线程下,使用四个线程对数组进行排序,所耗费时间是最少的!

  • 相关阅读:
    [转] Chrome
    阿里安全潘多拉实验室首先完美越狱苹果iOS 11.2
    【阿里聚安全·安全周刊】阿里双11技术十二讲直播预约|AWS S3配置错误曝光NSA陆军机密文件
    卡巴斯基发布安全公告:2018年威胁预测
    【阿里聚安全·安全周刊】双十一背后的“霸下-七层流量清洗”系统| 大疆 VS “白帽子”,到底谁威胁了谁?
    分享一个白帽交流灵感的社区——先知技术安全社区
    WiFi网络WPA2 KRACK漏洞分析报告
    #云栖大会# 移动安全专场——APP渠道推广作弊攻防那些事儿(演讲速记)
    #云栖大会# 移动安全专场——APP加固新方向(演讲速记)
    Java安全编码:糟糕的在线建议和令人困惑的APIs
  • 原文地址:https://www.cnblogs.com/itrena/p/5926947.html
Copyright © 2011-2022 走看看