測試一下我的電腦有多快


前言

弄了一台 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM