並行搜索
並行的基本概念
所謂併發是在同一實體上的多個事件同時發生。併發編程是指在同一計算機上“同時”處理多個任務。
要理解併發編程,我們必須要理解如下一些基本概念
計算機就像一座工廠,時刻在運行,爲人類服務。它的核心是CPU,它承擔了所有的計算機任務,就像工廠的一個現場指揮官。
進程就像工廠裏的車間,承擔“工廠”裏的各項具體的“生產任務”,通常每個進程對應一個在運行中的執行程序,比如,QQ和微信運行時,他們分別是不同的進程。
因爲特殊的原因,現場指揮官人才短缺,整個工廠只有一個指揮官,一次只能指導一個車間生產,而所有的車間都必須要有現場指揮官在場才能生產。也就是說,一個車間開工的時候其他車間都必須停工。
背後的含義:任一時刻,單個CPU一次只能運行一個進程,此時其他進程處於非運行狀態。
一個車間(進程)可以包含多條生產線,線程就好比車間(進程)裏的生產線。所有生產線(設備和人)都屬於同一車間的資源,受車間統一調度和調配,並共享車間所有資源(如空間和洗手間)。
背後含義:一個進程可以擁有多個線程,每個線程可以獨立並行執行,多個線程共線同一進程的資源,受進程管理。
理解了以上這些概念,接下來再繼續講解並行搜索的概念:
假設我們要從很大的一個無序的數據集中進行搜索,假設我們的機器可以一次性容納這麼多數據。從理論上講,對於無序數據,如果不考慮排序,已經很難從算法層面優化了。而利用上面我們提到的並行處理思想,我們可以很輕鬆地將檢索效率提升多倍。具體實現思路如下:
將數據分成N個塊,每個塊由一個線程來並行搜索。
參考v1.1:
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <time.h>
#define TEST_SIZE (1024*1024*200) /* 200M - 2億個 */
#define NUMBER 20
int main()
{
int* data = NULL;
int count = 0; /* 記錄的數量 */
data = new int[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++)
{
data[i] = i;
}
time_t start = 0, end = 0; /* 記錄開始和結束的時間戳 */
time(&start);
for (int j = 0; j < 10; j++)
{
for (int i = 0; i < TEST_SIZE; i++)
{
if (data[i] == NUMBER)
{
count++;
}
}
}
time(&end);
printf("查找所花時間: %lld\n", end - start);
system("pause");
return 0;
}
運行環境: vs2019
運行結果:
參考v1.2:
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <time.h>
#define TEST_SIZE (1024*1024*200) /* 200M - 2億個 */
#define NUMBER 20
DWORD WINAPI ThreadProc(void* lpParem)
{
for (int i = 0; i < 5; i++)
{
printf("進程老爸, 我來了!\n");
Sleep(1000);
}
return 0;
}
int main()
{
DWORD threadID1; /* 線程1的身份證 */
HANDLE hThread1; /* 線程1的句柄 */
DWORD threadID2; /* 線程2的身份證 */
HANDLE hThread2; /* 線程2的句柄 */
printf("創建線程...\n");
/* 創建線程1 */
hThread1 = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadID1);
/* 創建線程2 */
hThread2 = CreateThread(NULL, 0, ThreadProc, NULL, 0, &threadID2);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
printf("進程老爸歡迎線程歸來\n");
system("pause");
return 0;
}
#if 0
int main()
{
int* data = NULL;
int count = 0; /* 記錄的數量 */
data = new int[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++)
{
data[i] = i;
}
time_t start = 0, end = 0; /* 記錄開始和結束的時間戳 */
time(&start);
for (int j = 0; j < 10; j++)
{
for (int i = 0; i < TEST_SIZE; i++)
{
if (data[i] == NUMBER)
{
count++;
}
}
}
time(&end);
printf("查找所花時間: %lld\n", end - start);
system("pause");
return 0;
}
#endif
運行結果:
參考v1.4:
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <time.h>
#define TEST_SIZE (1024*1024*200) /* 200M - 2億個 */
#define NUMBER 20
typedef struct _search
{
int* data; /* 搜索的數據集 */
size_t start; /* 搜索的開始位置 */
size_t end; /* 搜索的終止位置 */
size_t count; /* 搜索結果 */
}search;
DWORD WINAPI ThreadProc(void* lpParem)
{
search* s = (search*)lpParem;
time_t start, end;
printf("新的線程開始執行...\n");
time(&start);
for (int j = 0; j < 10; j++)
{
for (size_t i = s->start; i < s->end; i++)
{
if (s->data[i] == NUMBER)
{
s->count++;
}
}
}
time(&end);
printf("查找所花的時間: %lld\n", end - start);
return 0;
}
int main()
{
int* data = NULL;
int count = 0; /* 記錄的數量 */
int mid = 0;
search s1, s2;
data = new int[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++)
{
data[i] = i;
}
mid = TEST_SIZE / 2;
s1.data = data;
s1.start = 0;
s1.end = mid;
s1.count = 0;
s2.data = data;
s2.start = mid + 1;
s2.end = TEST_SIZE - 1;
s2.count = 0;
DWORD threadID1; /* 線程1的身份證 */
HANDLE hThread1; /* 線程1的句柄 */
DWORD threadID2; /* 線程2的身份證 */
HANDLE hThread2; /* 線程2的句柄 */
printf("創建線程...\n");
/* 創建線程1 */
hThread1 = CreateThread(NULL, 0, ThreadProc, &s1, 0, &threadID1);
/* 創建線程2 */
hThread2 = CreateThread(NULL, 0, ThreadProc, &s2, 0, &threadID2);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
printf("進程老爸歡迎線程歸來\n count: %d", s1.count + s2.count);
system("pause");
return 0;
}
#if 0
int main()
{
int* data = NULL;
int count = 0; /* 記錄的數量 */
data = new int[TEST_SIZE];
for (int i = 0; i < TEST_SIZE; i++)
{
data[i] = i;
}
time_t start = 0, end = 0; /* 記錄開始和結束的時間戳 */
time(&start);
for (int j = 0; j < 10; j++)
{
for (int i = 0; i < TEST_SIZE; i++)
{
if (data[i] == NUMBER)
{
count++;
}
}
}
time(&end);
printf("查找所花時間: %lld\n", end - start);
system("pause");
return 0;
}
#endif
運行結果:
count = 10, 因爲我循環10次
結語:
學到的知識要, 多複習, 多總結, 多敲. 需要時間的積累, 才能引起質的改變. 自己寫不出來的永遠是別人的.
分享一下我的技巧: 代數法把具體的數字帶進去, 看看能能能找到規律(掌握思想).
還有就是畫圖, 也很重要. 用筆畫出來, 把數代進去, 方法雖然笨, 但真的很實用, 好記憶不如爛筆頭!!! 還有多用debug(調試工具)
我是小白, C/C++功力…, 你懂得, 寫的文章可能不是很好. 如果存在問題, 歡迎大神給予評判指正.
錯了不可怕, 可怕的是找不出bug, 誰沒錯過!!!
最近學操作系統我認爲, 學什麼都要成本(時間), 即使它是免費的, 我個人認爲要挑來學, 挑重點來學, 而不是從頭到尾, 除非考試考研.
這個知識點我沒有完全掌握, 就是會了也要複習, 革命尚未成功, 同志還需努力!!! , 我會回來反覆複習的
今日是: 2020年5月18日, (由於疫情的原因)現在沒有返校. 寫博客,也可自己加強記憶,就當寫寫日記吧!!!
希望給個贊: 反正你又不虧, 順便而已