京山游侠

专注技术 拒绝扯淡
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

测试一下我的电脑有多快

Posted on 2020-09-10 16:25  京山游侠  阅读(2160)  评论(1编辑  收藏  举报

前言

弄了一台 Dell XPS 9570, 4K屏。终于满足了我在高分屏下玩 Linux 桌面的愿望。我已经给这台电脑安装了最新的 Ubuntu 20.10,并进行了适当的美化。昨天,又折腾了一晚上 Vim,主要是配置了 YouCompleteMe 和 vim-airline,所以迫不及待地想写写代码找找手感。那就测试一下我的电脑能运行多快,计时的精度有多高吧,顺便看看,通过我自己手撸的快速排序算法,程序又能提速到多快。

Linux 下的计时及其精度

以前用的计时函数是 gettimeofday(),其精度可以达到毫秒。有一天我在翻看《Unix环境高级编程》的时候,发现里面提到,gettimeofday() 早就废弃不用了,现在推荐使用 clock_gettime() 函数,精度可以达到 1 纳秒。听起来都好诱人。

下面写个小程序测试一下,就是连续两次调用 clock_gettime() 函数,然后打印时间间隔,看我的电脑记一次时,最快能达到多少纳秒。程序如下:

#include <iostream>
#include <iomanip>
#include <sys/time.h>

using namespace std;

void print_timer(struct timespec start, struct timespec end){
    long timer = (end.tv_sec - start.tv_sec)*1000000000 + end.tv_nsec - start.tv_nsec;
    cout << setw(3) << setfill('0') << timer/1000000000 << ",";
    cout << setw(3) << setfill('0') << (timer/1000000)%1000 << ",";
    cout << setw(3) << setfill('0') << (timer/1000)%1000 << ",";
    cout << setw(3) << setfill('0') << timer % 1000 << " ns" << endl;
}

int main(){
    struct timespec start;
    struct timespec end;

    clock_gettime(CLOCK_REALTIME, &start);
    clock_gettime(CLOCK_REALTIME, &end);

    print_timer(start, end);

    return 0;
}

本来写这篇文章就是想找找 Vim 的手感,所以必须来一张 Vim 的图片,如下:

运行结果如下:

从上面的结果可以看出,我的电脑计时的精度可以达到 348ns,真的好厉害。以后,我的所有需要测试程序运行时间的,都使用上面这样的模板代码。

测试对长度为 1000000 的数组进行排序的时间:1.冒泡排序

冒泡排序的代码我就不列出了,因为是在是太简单了,就是两重循环,其时间复杂度为 \(O(n^2)\) ,那么,我们测出的时间是多少呢?

2645,822,408,482 ns

两千多秒,也就是四十多分钟,实在是太慢了。

测试对长度为 1000000 的数组进行排序的时间:2.快速排序

当然,上面程序的慢是每一个算法书上都会提到的,所以我们需要使用更快的算法。我这里使用的是快速排序,其时间复杂度为 \(O(n\log{n})\) 。算法是我手撸的,如下:

#include <iostream>
#include <iomanip>
#include <sys/time.h>
using namespace std;

const int ARR_LEN = 1000000;

template <typename T>
void init_arr(T* a, int len){
    for(int i=0; i<len; i++){
        a[i] = (T)rand();
    }
}

template <typename T>
void print_arr(T* a, int len){
    if(len<10){
        for(int i=0; i<len; i++){
            cout << a[i] << "   ";
        }
        cout << endl;
    }else{
        for(int i=0; i<5; i++){
            cout << a[i] << "   ";
        }
        cout << "...   ";
        for(int i=len-5; i<len; i++){
            cout << a[i] << "   ";
        }
        cout << endl;
    }
}


template <typename T>
void quick_sort(T* a, int len){
    if(len<2)return;
    if(len == 2){
        if(a[0] > a[1]){
            T temp = a[0];
            a[0] = a[1];
            a[1] = temp;
        }
    }
    
    int i=0, left=0, right=len-1;
    while(left < right){
        while(a[right] > a[i] && left < right){
            right--;
        }
        if(left<right){
            T temp = a[right];
            a[right] = a[i];
            a[i] = temp;
            i = right;
            left ++;
        }

        while(a[left] < a[i] && left<right){
            left++;
        }
        if(left<right){
            T temp = a[left];
            a[left] = a[i];
            a[i] = temp;
            i = left;
            right--;
        }
    }
    
    quick_sort(a, i);
    quick_sort(a+i+1, len-i-1);
}


void print_timer(struct timespec start, struct timespec end){
    long timer = (end.tv_sec - start.tv_sec)*1000000000 + end.tv_nsec - start.tv_nsec;
    cout << setw(3) << setfill('0') << timer/1000000000 << ",";
    cout << setw(3) << setfill('0') << (timer/1000000)%1000 << ",";
    cout << setw(3) << setfill('0') << (timer/1000)%1000 << ",";
    cout << setw(3) << setfill('0') << timer % 1000 << " ns" << endl;
}

int main(){
    int* a = (int*)malloc(sizeof(int)*ARR_LEN);
    init_arr(a, ARR_LEN);
    print_arr(a, ARR_LEN);

    struct timespec start;
    struct timespec end;
    clock_gettime(CLOCK_REALTIME, &start);

    quick_sort(a, ARR_LEN);

    clock_gettime(CLOCK_REALTIME, &end);

    print_arr(a, ARR_LEN);
    print_timer(start, end);
    return 0;
}

编译,运行。它的时间是多少呢?

000,123,209,970 ns

也就是 123ms,比冒泡排序足足提速两万一千五百多倍。我的天哪!看来算法还是非常重要的呀。

测试对长度为 1000000 的数组进行排序的时间:3.使用多线程的快速排序

这是最快的速度了吗?显然不是,我的电脑 CPU 可是 6 核 12 线程的。不充分利用多核优势怎么对得起自己。我上面的快速排序算法使用的是递归,那么使用 OpenMP 就没戏了(主要是我自己水平太菜,没找到递归算法的 OpenMP 写法)。那么只好自己写 thread 了,好在是自从 C++ 11 之后,写 thread 也很简单。我的方法就是在 quick_sort() 函数中判断一下待排序的数组的长度,如果待排序的数组的长度大于总数组长度的 1/8,就在新创建的线程里递归调用 quick_sort(),否则就直接递归调用 quick_sort()。如下图:

编译,运行。它的时间是多少呢?

000,040,038,803 ns

速度再次提升三倍,终于使时间达到了 40ms 的级别。这可能就是我的电脑和我本人的水平所能达到的最快速度吧。

下面是运行截图:

总结

电脑很 NB,Linux 的计时器也很 NB,算法很 NB,配置了 YouCompleteMe 和 vim-airline 的 Vim 也很 NB。

版权申明

该随笔由京山游侠在2021年05月16日发布于博客园,引用请注明出处,转载或出版请联系博主。QQ邮箱:1841079@qq.com