当前位置: 首页 > news >正文

使用多线程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发挥多核计算优势&#xff08;题目&#xff09; 单核无能为力 如果我们的电脑只有一个核&#xff0c;那么我们没有什么更好的办法可以让我们的程序更快。 因为这个作业限制了你修改算法函数。你唯一能做的就是利用你电脑的多核。 使用多线程 由于我们…...

MySQL分页查询详解:优化大数据集的LIMIT和OFFSET

最近在工作中&#xff0c;我们遇到了一个需求&#xff0c;甲方要求直接从数据库导出一个业务模块中所有使用中的工单信息。为了实现这一目标&#xff0c;我编写了一条SQL查询语句&#xff0c;并请求DBA协助导出数据。尽管工单数量并不多&#xff0c;只有3000多条&#xff0c;但…...

解构赋值、函数默认值

暂时性死区&#xff0c;TDZ&#xff08;Temporal Dead Zone&#xff09; var x 1 {let x x//此处声明了x&#xff0c;但是没有对x赋值&#xff0c;相当于在赋值之前引用x&#xff0c;所以会造成报错console.log(x)//报错x is not defined&#xff0c;暂时性死区&#xff0c;…...

【已解决】Mybatis 实现 Group By 动态分组查询

&#x1f389;工作中遇到这样一个需求场景&#xff1a;实现一个统计查询&#xff0c;要求可以根据用户在前端界面筛选的字段进行动态地分组统计。也就是说&#xff0c;后端在实现分组查询的时候&#xff0c;Group By 的字段是不确定的&#xff0c;可能是一个字段、多个字段或者…...

Android修改默认gradle路径

Android Studio每次新建项目&#xff0c;都会默认在C盘生成并下载gradle相关文件&#xff0c;由于C盘空间有限&#xff0c;没多久C盘就飘红了&#xff0c;于是就需要把gradle相关文件转移到其他盘 1、到C盘找到gradle文件 具体路径一般是&#xff1a;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的缩写&#xff0c;也就是网络附属存储。可以使用自己已经不怎么使用的笔记本搭建一台NAS服务器。 fdisk -l可以看一下各个磁盘的状态。 可以看到有sda、sdb、sdc和sdd等四块硬盘。 lvs、vgs和pvs结合起来看&#xff0c;sdb和sdc没有被使用。 …...

分享码云上8个宝藏又有价值的开源图片编辑器

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

TCP Header都有啥?

分析&回答 源端口号&#xff08;Source Port&#xff09; &#xff1a;16位&#xff0c;标识主机上发起传送的应用程序&#xff1b; 目的端口&#xff08;Destonation Port&#xff09; &#xff1a;16位&#xff0c;标识主机上传送要到达的应用程序。 源端&#xff0c;目…...

无涯教程-Android - AutoCompleteTextView函数

AutoCompleteTextView是一个类似于EditText的视图&#xff0c;只是它在用户键入时自动显示补充数据。 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 启动会报错&#xff0c;按照下面流程修改 3、在宿主机中&#xff0c;修改配置sysctl.conf vim /etc/sysctl.conf 加入如下配…...

【数据结构篇】线性表1 --- 顺序表、链表 (万字详解!!)

前言&#xff1a;这篇博客我们重点讲 线性表中的顺序表、链表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列... 线性表在逻辑上是…...

C语言每日一练--Day(17)

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

8月琐碎但值得的事情

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

苹果Mac系统如何优化流畅的运行?提高运行速度

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

Python 类和对象

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

VC++使用Microsoft Speech SDK进行文字TTS朗读

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

FFmpeg4.3.1+h264在windows下编译与VS2017项目集成

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。本文是音视频系…...

mapboxGL3新特性介绍

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

类ChatGPT大模型LLaMA及其微调模型

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

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...