c++ 查找算法 并行搜索 个人笔记
一.并行搜索需要了解的东西
这个笔记会涉及一些Windows进程和线程的东西 ,了解一点就可以(还没有学到mfc)
计算机就像一座工厂,时刻在运行,为人类服务。它的核心是 CPU,它承担了所有的计算任
务,就像工厂的一个现场指挥官
进程就像工厂里的车间,承担“工厂”里的各项具体的“生产任务”,通常每个进程对应一
个在运行中的执行程序,比如,QQ 和微信运行的时候,他们分别是不同的进程。
因为特殊原因,现场指挥官人才短缺,整个工厂只有一个指挥官(一个cpu),一次只能指导一个车间生
产,而所有的车间都必须要有现场指挥官在场才能生产。也就是说,一个车间开工的时候,
其他车间都必须停工。
进程的含义:任一时刻,单个 CPU 一次只能运行一个进程,此时其他进程处于非运行状态。
一个车间(进程)可以包括多条生产线,**线程****就好比车间(进程)里的生产线。所有生产线
(设备和人)都属于同一车间的资源,受车间统一调度和调配,并共享车间所有资源(如空
间或洗手间)。
线程的含义:一个进程可以拥有多个线程,每个线程可以可以独立并行执行,多个线程共
享同一进程的资源,受进程管理。
二. 问题
假设我们要从很大的一个无序的数据集中进行搜索一个数出现了几次,假设我们的机器可以一次性容纳这么多
数据,无序数组只能从头遍历到尾
三. 使用串行搜索的代码实现
#include <iostream>
#include <stdio.h>
#include <time.h>
using namespace std;
//内存的基本储存单位b 1024b*1024b = 1mb *200 = 200mb
#define TEST_SIZE (1024*1024*200) //数组大小d
#define SEARCH_NUMBER 20 //需要查找的数据20
int main01(void) {
int* test = NULL;
int count = 0; //记录查找的数据在test数组中出现几次
test = new int[TEST_SIZE];
//为数组赋值 虽然是有序的但假设不是有序的
for (int i = 0; i < TEST_SIZE; i++) {
test[i] = i;
}
time_t start = 0; //开始计数 时间戳
time_t end = 0; //结束计数
time(&start);
//第一个循环没有实际作用,就起延时作用 ,end - start 所需的时间更直观
for (int j = 0; j < 10; j++) {
//遍历10次 test 数组
for (int i = 0; i <= TEST_SIZE; i++) {
if (test[i] == SEARCH_NUMBER) {
count++;
}
}
}
time(&end);
//end- start 就是中间程序运行所花时间(秒)
printf("所花时间: %lld,数组中出现了:%d 次\n", end - start, count);
delete[] test;
return 0;
}
测试结果:
//所花时间是6秒 , 因为遍历了10次这个数组,20这个元素也就出现了10次
四.使用并行搜索
#include <iostream>
#include <stdio.h>
#include <Windows.h>
#include <time.h>
using namespace std;
//内存的基本储存单位b 1024b*1024b = 1mb *200 = 200mb
#define TEST_SIZE (1024*1024*200) //数组大小d
#define SEARCH_NUMBER 20 //需要查找的数据20
//查找的结构体
typedef struct _Search {
int* data; //数组
size_t begin; //开始遍历的下标
size_t end; //遍历结束的下标;
int count; //需要查找的数出现的次数
}Search;
/*
******************************
*函数作用: 线程的函数
*
*函数参数: 必须是void*类型的 参数
*
*函数返回值: 必须是DWORD WINAPI类型 WINAPI 可以省略
*** *********************
*/
DWORD WINAPI threadFun(void* prc) {
Search* search = (Search*)prc;
time_t start = 0; //开始计数 时间戳
time_t end = 0; //结束计数
time(&start);
for (int j = 0; j < 10; j++) {
//遍历10次 test 数组
for (int i = search->begin; i < search->end; i++) {
if (search->data[i] == SEARCH_NUMBER) {
search->count++;
}
}
}
time(&end);
printf("所花时间: %lld\n", end - start);
return 0;
}
int main(void) {
int* test = NULL;
int count = 0; //记录查找的数据在test数组中出现几次
size_t middle = 0; //把数组从中间分开
//DWORD 其实就是unsigend long 型
DWORD threadId1 = 0; //线程id1 //线程1的身份证
HANDLE hthreadId1;//线程1的句柄
DWORD threadId2 = 0; //线程id2 /线程2的身份证
HANDLE hthreadId2; //线程2的句柄
Search* s1, * s2;
s1 = new Search;
s2 = new Search;
test = new int[TEST_SIZE];
//为数组赋值 虽然是有序的但假设不是有序的
for (int i = 0; i < TEST_SIZE; i++) {
test[i] = i;
}
middle = TEST_SIZE / 2;
s1->data = test;
s1->begin = 0;
s1->end = middle;
s1->count = 0;
s2->data = test;
s2->begin = middle;
s2->end = TEST_SIZE;
s2->count = 0;
//创建一个线程
/*
***********************************
*函数参数: 第一个是: 线程属性
* 第二个是: 线程堆的大小
* 第三个是: 需要执行这个线程的代码(函数指针)
* 第四个是: 函数指针的参数
* 第五个是: 线程的编号(唯一的)地址
*
*函数返回值: 控制这个线程的句柄
*********************************
*/
//创建线程1
hthreadId1 = CreateThread(NULL, 0, threadFun, s1, NULL, &threadId1);
//创建线程2
hthreadId2 = CreateThread(NULL, 0, threadFun, s2, NULL, &threadId2);
/*
*********************************
*函数的参数: 第一个参数: 需要等待线程的句柄
* 第二个参数: 等待的时间
*
*函数作用: 等待线程执行完毕
*
*函数返回值: 不清楚
*****************************
*/
//INFINITE 是int 类型最大的的数
//直到这个线程执行完毕返回到进程
WaitForSingleObject(hthreadId1, INFINITE);
WaitForSingleObject(hthreadId2, INFINITE);
printf("数组中出现了:%d 次\n", s1->count+s2->count);
delete s1;
delete s2;
delete[] test;
return 0;
}
为什么要用WaitForSingleObject();
进程创建线程就像地主雇佣工人,地主只管雇佣,雇佣完后,工人工作,地主忙别的事,
进程创建线程完之后就没有进程什么事了,进程继续往下执行,线程执行线程函数,WaitForSingleObject起进程等待线程执行完毕之后继续往下执行
测试结果:
//二个线程是同时执行的 所需时间是4秒