C/C++_查找算法_並行搜索

並行搜索

並行的基本概念
所謂併發是在同一實體上的多個事件同時發生。併發編程是指在同一計算機上“同時”處理多個任務。

要理解併發編程,我們必須要理解如下一些基本概念

計算機就像一座工廠,時刻在運行,爲人類服務。它的核心是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日, (由於疫情的原因)現在沒有返校. 寫博客,也可自己加強記憶,就當寫寫日記吧!!!

希望給個贊: 反正你又不虧, 順便而已

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章