使用多线程std::thread发挥多核计算优势(解答)
使用多线程std::thread发挥多核计算优势(题目)
单核无能为力
如果我们的电脑只有一个核,那么我们没有什么更好的办法可以让我们的程序更快。
因为这个作业限制了你修改算法函数。你唯一能做的就是利用你电脑的多核。
使用多线程
由于我们的电脑有多个内核,所以,我们可以创建多线程来把任务“平均”分配给多个核来计算。
这样多个核在“同时”运算的时候就可以加速程序的执行。
多核的细节
关于我们创建多少个线程比较合适,多个线程真的可以各自分配到多个核而“同时”运行吗?
试一下就知道了。
双线程的效果
我们先用两个线程,把任务固定的分配给这两个线程,看看完成任务总的执行时间是不是变短了。
代码如下:
#include <iostream>
#include <cmath>//sqrt
#include <iostream>
#include <iomanip>//format output
#include <chrono>
#include <thread>//for faster code
#include <mutex>//for faster code
#include <sstream>//stringstream
using namespace std::chrono;//time_piont duration
using namespace std;//test helper function begin 测试辅助代码开始
void check_do(bool b, int line = __LINE__)
{if (b) { cout << "line:" << line << " Pass" << endl; }else { cout << "line:" << line << " Ohh! not passed!!!!!!!!!!!!!!!!!!!!!!!!!!!" << " " << endl; exit(0); }
}
#define check(msg) check_do(msg, __LINE__);
//test helper function end 测试辅助代码结束//do not change this function! 不要修改这个函数
//if you want to check a number is prime number or not, you can use this function only.
//判断素数只能用这个函数
bool is_number_prime(int n)
{if (n == 2 || n == 3)//prime less than 5{return true;//is prime}if (n % 6 != 5 && n % 6 != 1)//is not prime{return false;}int cmb = (int)std::sqrt(n);for (int i = 5; i <= cmb; i += 6){if (n % i == 0 || n % (i + 2) == 0){return false;//is not prime}}return true;//is prime
}/*100以内的素数 primes within 1002 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
*/
//测试判断素数的函数是否正确
void test_is_prime_number(void)
{stringstream ss;for (int i = 2; i < 100; i++){if (is_number_prime(i)){ss << i << " ";}}check(ss.str() == "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ");
}//do not change this function!
//不要修改此函数
long long test_the_sum_of_all_primes_within(long long scale)
{auto start = system_clock::now();long long sum = 0;for (int n = 2; n <= scale; n++) {if (is_number_prime(n)) {sum += n;}}cout << "the sum of all primes from 2~"<< setw(10) << scale << " is : " << setw(15) << sum<< ", elapled " << setw(10) << static_cast<long long>(duration<double, milli>(system_clock::now() - start).count()) << " milliseconds"<< endl;return sum;
}
//please change this function to let your program faster by use multi core in your CPU.
//请重新实现此函数以让你的CPU多核优势得到发挥
//hint: maybe you can use multi thread technology to let your code faster.
//提示:你可以使用多线程来发挥多核的计算优势从而让你的程序跑的更快
long long faster_test_the_sum_of_all_primes_within(long long scale)
{auto start = system_clock::now();long long sum = 0;std::mutex sum_mutex;auto fun = [&sum, &sum_mutex](long long scaleStart, long long scaleLast) {for (int n = scaleStart; n <= scaleLast; n++) {if (is_number_prime(n)) {std::lock_guard<std::mutex> lock(sum_mutex);//如果没有多线程互斥访问sum,那么sum的值就可能是错的。sum += n;}}};//区间平分,这样后面的第二个线程的计算量还是偏大,因为都是在处理更大的数字std::thread t1(fun, 2, scale / 2);std::thread t2(fun, scale / 2 + 1, scale);t1.join();//线程开始运行直到结束t2.join();//线程开始运行直到结束cout << "the sum of all primes from 2~" << setw(10) << scale << " is : " << setw(15) << sum<< ", elapled " << setw(10) << static_cast<long long>(duration<double, milli>(system_clock::now() - start).count()) << " milliseconds"<< endl;return sum;
}
//do not change the code in this function
//不要修改此函数中的内容
int main()
{test_is_prime_number();long long sum = 0;cout << "base slow version:" << endl;sum = test_the_sum_of_all_primes_within(10000 * 10);check(sum == 454396537);sum = test_the_sum_of_all_primes_within(10000 * 100);check(sum == 37550402023);sum = test_the_sum_of_all_primes_within(10000 * 1000);check(sum == 3203324994356);sum = test_the_sum_of_all_primes_within(10000 * 10000);check(sum == 279209790387276);cout << endl << "my faster version:" << endl;sum = faster_test_the_sum_of_all_primes_within(10000 * 10);check(sum == 454396537);sum = faster_test_the_sum_of_all_primes_within(10000 * 100);check(sum == 37550402023);sum = faster_test_the_sum_of_all_primes_within(10000 * 1000);check(sum == 3203324994356);sum = faster_test_the_sum_of_all_primes_within(10000 * 10000);check(sum == 279209790387276);cout << "please enter enter for exit." << endl;cin.get();return 0;
}
运行结果:
代码分析
如同代码注释中所说,我们把求解区间一分为二,后面的一个线程整体上任务还是偏重。因为处理的都是大数据。
但即便这样简单的划分,两个线程比一个线程耗时还是大幅度降低的。
在一百万个整数求解的时候时间降低了50%;
在一千万个整数求解的时候时间降低了50%;
在一亿个整数求解的时候时间降低了30%;这是因为后面一个线程的计算量过大,两个线程的任务没有起到平分导致的。
可以预见,随着数据量的继续增大,这种平分区间的算法,会导致第二个线程完全占据计算量的大头。这时候会导致这种算法的优势降低,甚至减少的时间可以忽略不计。
但是我们的目的达到了。那就是我们已经验证了多线程多核在计算速度上的确是可以完胜单线程的,只要我们合理分配计算任务给多个线程。
继续增加线程数量
下面我们把区间3等分,创建3个线程,看看是不是耗时会不会继续降低:
long long faster_test_the_sum_of_all_primes_within(long long scale)
{auto start = system_clock::now();long long sum = 0;std::mutex sum_mutex;auto fun = [&sum, &sum_mutex](long long scaleStart, long long scaleLast) {for (int n = scaleStart; n <= scaleLast; n++) {if (is_number_prime(n)) {std::lock_guard<std::mutex> lock(sum_mutex);//如果没有多线程互斥访问sum,那么sum的值就可能是错的。sum += n;}}};//区间平分,这样后面的第二个线程的计算量还是偏大,因为都是在处理更大的数字std::thread t1(fun, 2, scale / 3);std::thread t2(fun, scale / 3 + 1, scale / 3 * 2);std::thread t3(fun, scale / 3 * 2 + 1, scale);t1.join();//线程开始运行直到结束t2.join();//线程开始运行直到结束t3.join();//线程开始运行直到结束cout << "the sum of all primes from 2~" << setw(10) << scale << " is : " << setw(15) << sum<< ", elapled " << setw(10) << static_cast<long long>(duration<double, milli>(system_clock::now() - start).count()) << " milliseconds"<< endl;return sum;
}
运行输出:
代码分析2
正如我们预期,时间继续下降,尤其是数据量达到一亿的时候,总耗时再次变为了原来的一半。
至此,多线程多核可以降低计算总时长已经被我们验证完毕。
怎么样?你学到了吗?
欢迎点赞收藏转发。让其他感兴趣的人也可以看到。
相关文章:

使用多线程std::thread发挥多核计算优势(解答)
使用多线程std::thread发挥多核计算优势(题目) 单核无能为力 如果我们的电脑只有一个核,那么我们没有什么更好的办法可以让我们的程序更快。 因为这个作业限制了你修改算法函数。你唯一能做的就是利用你电脑的多核。 使用多线程 由于我们…...

MySQL分页查询详解:优化大数据集的LIMIT和OFFSET
最近在工作中,我们遇到了一个需求,甲方要求直接从数据库导出一个业务模块中所有使用中的工单信息。为了实现这一目标,我编写了一条SQL查询语句,并请求DBA协助导出数据。尽管工单数量并不多,只有3000多条,但…...
解构赋值、函数默认值
暂时性死区,TDZ(Temporal Dead Zone) var x 1 {let x x//此处声明了x,但是没有对x赋值,相当于在赋值之前引用x,所以会造成报错console.log(x)//报错x is not defined,暂时性死区,…...
【已解决】Mybatis 实现 Group By 动态分组查询
🎉工作中遇到这样一个需求场景:实现一个统计查询,要求可以根据用户在前端界面筛选的字段进行动态地分组统计。也就是说,后端在实现分组查询的时候,Group By 的字段是不确定的,可能是一个字段、多个字段或者…...

Android修改默认gradle路径
Android Studio每次新建项目,都会默认在C盘生成并下载gradle相关文件,由于C盘空间有限,没多久C盘就飘红了,于是就需要把gradle相关文件转移到其他盘 1、到C盘找到gradle文件 具体路径一般是:C:\Users\用户\ .gradle …...

原生JS+canvas实现炫酷背景
原生JScanvas实现炫酷背景 可以在需要的背景页使用 <!doctype html> <html> <head> <meta charset"utf-8"> <title>HTML5 Canvas矩阵粒子波浪背景动画特效</title> <style> html,body { height:100%; } body { …...

Linux学习之NAS服务器搭建
NAS是Network Attached Storage的缩写,也就是网络附属存储。可以使用自己已经不怎么使用的笔记本搭建一台NAS服务器。 fdisk -l可以看一下各个磁盘的状态。 可以看到有sda、sdb、sdc和sdd等四块硬盘。 lvs、vgs和pvs结合起来看,sdb和sdc没有被使用。 …...

分享码云上8个宝藏又有价值的开源图片编辑器
如果你需要高效地处理图片,那么这8款实用工具是可以尝试的! 它们能够进行一键抠图、放大、拼接、转矢量图、图标自动生成以及等操作,让你的工作效率飞升! 在Gitee这个最有价值的开源项目计划是Gitee综合评定出的优秀开源项目的展示…...

TCP Header都有啥?
分析&回答 源端口号(Source Port) :16位,标识主机上发起传送的应用程序; 目的端口(Destonation Port) :16位,标识主机上传送要到达的应用程序。 源端,目…...

无涯教程-Android - AutoCompleteTextView函数
AutoCompleteTextView是一个类似于EditText的视图,只是它在用户键入时自动显示补充数据。 AutoCompleteTextView - 属性 以下是与AutoCompleteTextView控件相关的重要属性。您可以查看Android官方文档以获取属性的完整列表以及可以在运行时更改这些属性的相关方法。…...
【Docker】 07-安装ElasticSearch、Kibana
安装ElasticSearch 1、拉取镜像 docker pull elasticsearch:6.4.2 2、运行 docker run -p 9200:9200 -p 9300:9300 --name es -d elasticsearch:6.4.2 启动会报错,按照下面流程修改 3、在宿主机中,修改配置sysctl.conf vim /etc/sysctl.conf 加入如下配…...

【数据结构篇】线性表1 --- 顺序表、链表 (万字详解!!)
前言:这篇博客我们重点讲 线性表中的顺序表、链表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列... 线性表在逻辑上是…...

C语言每日一练--Day(17)
本专栏为c语言练习专栏,适合刚刚学完c语言的初学者。本专栏每天会不定时更新,通过每天练习,进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字:数对 截取字符串 💓博主csdn个人主页:小小unico…...

8月琐碎但值得的事情
8月份结束了,最近心态比较好,慢点就慢点,没有那么着急了,可能是因为着急也没啥办法, 8月是比较开心的一个月,可能是做的事情更有盼头了,可能是看了喜欢的书,可能是我变瘦了ÿ…...

苹果Mac系统如何优化流畅的运行?提高运行速度
Mac系统的稳定性和流畅性一直备受大家称赞,这也是大多数人选择Mac的原因,尽管如此,我们仍不时地对Mac进行优化、调整,以使其比以前更快、更流畅地运行。以下是小编分享给各位的Mac优化方法,记得保存哦~ 一、释放被过度…...

Python 类和对象
类的创建 Python语言中,使用class关键字来创建类,其创建方式如下: class ClassName(bases):# class documentation string 类文档字符串,对类进行解释说明class_suiteclass是关键字,bases是要继承的父类,…...

VC++使用Microsoft Speech SDK进行文字TTS朗读
Microsoft Speech SDK下载地址 https://www.microsoft.com/en-us/download/details.aspx?id10121 需要msttss22L.exe、SpeechSDK51.exe、SpeechSDK51LangPack.exe三个,下载后全部安装 使用VS2005建立一个win32控制台项目 朗读"hello word"、中文“你好”…...

FFmpeg4.3.1+h264在windows下编译与VS2017项目集成
前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》,结合我自己的工作学习经历,我准备写一个音视频系列blog。本文是音视频系…...

mapboxGL3新特性介绍
概述 8月7日,mapboxGL发布了3版本的更新,本文带大家一起来看看mapboxGL3有哪些新的特性。 新特新 如上图所示,是mapboxGL官网关于新版的介绍,大致翻译如下: 增强了web渲染的质量、便捷程度以及开发人员体验ÿ…...

类ChatGPT大模型LLaMA及其微调模型
1.LLaMA LLaMA的模型架构:RMSNorm/SwiGLU/RoPE/Transfor mer/1-1.4T tokens 1.1对transformer子层的输入归一化 对每个transformer子层的输入使用RMSNorm进行归一化,计算如下: 1.2使用SwiGLU替换ReLU 【Relu激活函数】Relu(x) max(0,x) 。 【GLU激…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...

2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...