多线程与并行计算(python与c++)基础入门篇

news2024/12/25 8:55:16

目录

1.简介

1.1什么事多线程

1.2概念

2.python多线程基础知识讲解

创建线程:

启动线程:

线程函数/方法:

线程同步:

线程间通信:

线程结束与等待:

线程常用方法:

3.c++多线程基础知识讲解

创建线程:

启动线程:

线程函数/方法:

线程同步:

线程间通信:

线程结束与等待:

线程常用方法:


1.简介

1.1什么事多线程

多线程是指在一个程序中同时执行多个线程,每个线程又可以独立地执行不同的任务。在单线程程序中,代码按照顺序依次执行,而多线程程序可以并发执行多个线程,提高了程序的运行效率和响应性。

 

1.2概念

  1. 线程与进程:线程是进程的一部分,一个进程可以包含多个线程。进程是一个正在执行中的程序,而线程是在进程内部活动的执行单元。多个线程共享进程的资源,如内存空间和文件句柄。

  2. 并发与并行:并发是指多个任务交替执行的状态,而并行是指多个任务同时执行的状态。多线程能够实现并发执行,但在单核处理器上只能通过时间片轮转的方式交替执行,而多核处理器可以实现真正的并行执行。

  3. 线程的创建与启动:在大多数编程语言中,都提供了创建和管理线程的机制。通过创建线程对象并给定需要执行的代码,可以创建一个新的线程。然后,通过启动线程,运行线程中定义的代码。

  4. 线程同步与互斥:由于多个线程共享资源,可能会导致竞争条件(Race Condition)和数据不一致的问题。为了避免这些问题,需要使用线程同步和互斥机制,如锁(Lock)和信号量(Semaphore),来保证线程间的有序访问共享资源。

  5. 线程通信:多个线程之间可能需要相互通信和协作。常见的线程通信机制有共享变量、消息队列、信号量等,通过这些机制可以实现线程间的数据传递和同步操作。

  6. 线程调度:线程调度决定了线程在多个可执行线程中的执行顺序和时间片分配。具体的调度策略与操作系统相关,可以是预先定义的优先级调度、时间片轮转、抢占式调度等。

  7. 线程安全性:线程安全性是指多线程环境中,对共享资源的访问和操作不会引发并发问题。编写线程安全的代码需要考虑数据的原子性、可见性和有序性,避免并发访问导致的错误。

2.python多线程基础知识讲解

Python 提供了 threading 模块,它是一个内置的模块,用于创建和管理线程。threading 模块提供了一些类和函数,使得创建和控制线程变得简单。

  1. 创建线程:

    • 使用 threading.Thread 类可以创建一个新的线程对象。在实例化线程对象时,需要指定线程要执行的函数或方法,并可以传递参数给该函数或方法。
    • 创建线程的基本语法为:thread_obj = threading.Thread(target=func, args=args),其中 target 指定函数或方法名,args 是一个元组,包含传递给函数或方法的参数。
  2. 启动线程:

    • 使用 start() 方法启动线程。调用线程对象的 start() 方法后,线程会开始执行指定的函数或方法。
    • 注意,不要直接调用线程函数或方法,而是使用 start() 方法启动线程,否则线程不会以并发的方式执行,而会以串行的方式执行。
  3. 线程函数/方法:

    • 线程要执行的代码写在线程函数(对于普通函数)或线程方法(对于类的方法)中。线程会按顺序执行这些代码。
    • 在线程函数或方法中可以使用 time.sleep() 函数来模拟耗时操作,以便让线程有时间片轮转的机会。
  4. 线程同步:

    • 多个线程可能会同时访问和修改共享的数据,因此需要进行线程同步以避免竞争条件和数据不一致。
    • 在 Python 中,可以使用锁(Lock)来实现线程同步。通过锁定共享资源,只允许一个线程访问,其他线程需要等待解锁后才能访问。
    • threading 模块提供了 Lock 类,可以在需要同步的代码块中使用 acquire()release() 方法来获取和释放锁。
  5. 线程间通信:

    • 多个线程之间可能需要进行通信和协作。如果线程之间需要传递数据,可以使用共享变量、队列、事件等线程安全的数据结构。
    • Python 提供了 Queue 类用于线程安全的队列操作,可以在不同的线程间安全地传递数据。
  6. 线程结束与等待:

    • 使用 join() 方法可以等待线程完成。调用线程对象的 join() 方法会阻塞调用线程,直到目标线程执行完毕。
    • 可以通过设置 timeout 参数来指定等待的超时时间,如果超过超时时间线程仍未结束,则继续执行。
  7. 线程常用方法:

    • start(): 启动线程。
    • join(timeout): 等待线程结束。
    • is_alive(): 检查线程是否在运行中。
    • getName(), setName(): 获取和设置线程名称。

这些是 Python 多线程编程的基本概念和常用操作。在实际开发中,需要注意线程安全性、资源的共享与同步、优化线程的数量等问题,以充分发挥多线程的优势。

下面给大家简单举个例子讲解一下

import threading
import time

# 线程函数
def thread_func(name, delay):
    print("线程 {} 开始".format(name))
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        print("线程 {} 执行,计数器:{}".format(name, count))
    print("线程 {} 结束".format(name))

# 创建并启动两个线程
if __name__ == "__main__":
    thread1 = threading.Thread(target=thread_func, args=("Thread 1", 1))
    thread2 = threading.Thread(target=thread_func, args=("Thread 2", 2))

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

print("主线程结束")

在这个例子中,我们通过 threading.Thread 类创建了两个线程 thread1thread2,每个线程都执行相同的 thread_func 函数。thread_func 函数接受两个参数,分别是线程的名称和延迟时间。

在线程函数内部,使用 time.sleep 函数模拟一段耗时操作,实际中可以是任何需要并发执行的任务。每个线程会依次执行这个耗时操作,并在控制台输出执行的信息。

在主线程中,我们先调用 thread1.start()thread2.start() 启动两个线程,然后调用 thread1.join()thread2.join() 等待两个线程执行结束。最后,主线程输出 "主线程结束"。

执行这段代码,你会看到两个线程按照不同的延迟时间交替执行,而主线程会等待两个子线程执行完毕后才会结束。

这个例子展示了如何使用 Python 的 threading 模块创建和管理多线程,实现简单的并发执行。请注意,在真正的应用中,需要注意线程同步、资源访问的安全性等问题,以避免并发问题。

3.c++多线程基础知识讲解

C++ 标准库提供了 <thread> 头文件,其中定义了一些类和函数,用于创建和管理线程。C++11 引入了对多线程的支持,使得使用多线程变得更加方便。

  1. 创建线程:

    • 使用 std::thread 类可以创建一个新的线程对象。在实例化线程对象时,需要指定线程要执行的函数或方法,并可以传递参数给该函数或方法。
    • 创建线程的基本语法为:std::thread thread_obj(func, args),其中 func 指定函数或方法名,args 是一个参数列表,包含传递给函数或方法的参数。
  2. 启动线程:

    • 使用 thread_obj.join() 方法启动线程。调用线程对象的 join() 方法后,线程会开始执行指定的函数或方法。
    • 注意,不要直接调用线程函数或方法,而是使用 join() 方法启动线程,否则线程不会以并发的方式执行,而会以串行的方式执行。
  3. 线程函数/方法:

    • 线程要执行的代码写在线程函数(对于普通函数)或线程方法(对于类的成员函数)中。线程会按顺序执行这些代码。
    • 在线程函数或方法中可以使用 std::this_thread::sleep_for() 函数来模拟耗时操作,以便让线程有时间片轮转的机会。
  4. 线程同步:

    • 多个线程可能会同时访问和修改共享的数据,因此需要进行线程同步以避免竞争条件和数据不一致。
    • 在 C++ 中,可以使用互斥锁(std::mutex)来实现线程同步。通过锁定共享资源,只允许一个线程访问,其他线程需要等待解锁后才能访问。
    • 互斥锁提供了 lock()unlock() 方法来获取和释放锁。
  5. 线程间通信:

    • 多个线程之间可能需要进行通信和协作。如果线程之间需要传递数据,可以使用共享变量、条件变量等线程安全的数据结构。
    • C++ 中的条件变量(std::condition_variable)用于在线程之间进行条件等待和唤醒操作,实现线程间的同步与通信。
  6. 线程结束与等待:

    • 使用 thread_obj.join() 方法可以等待线程完成。调用线程对象的 join() 方法会阻塞调用线程,直到目标线程执行完毕。
    • 可以通过设置 timeout 参数来指定等待的超时时间,如果超过超时时间线程仍未结束,则继续执行。
  7. 线程常用方法:

    • join(): 等待线程结束。
    • joinable(): 检查线程是否可以被 join()
    • detach(): 分离线程,使其在执行完毕后自动释放资源。
    • get_id(): 获取线程的唯一标识符。

这些是 C++ 中多线程操作的基本概念和常用操作。在实际开发中,需要注意线程安全性、资源的共享与同步、优化线程的数量等问题,以充分发挥多线程的优势。

下面是一个简单的 C++ 多线程的例子,我们将使用多个线程计算数组中元素的和,并输出结果。

#include <iostream>
#include <thread>
#include <vector>

// 线程函数:计算数组片段的和
void calculateSum(const std::vector<int>& arr, int start, int end, int& sum)
{
    sum = 0;
    for (int i = start; i < end; i++) {
        sum += arr[i];
    }
}

int main()
{
    std::vector<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int numThreads = 4;  // 线程数量
    int arrSize = arr.size();
    std::vector<std::thread> threads(numThreads);  // 创建线程对象的容器
    std::vector<int> partialSums(numThreads);  // 存储每个线程计算得到的和

    // 启动线程,并计算每个线程要计算的数组片段
    int step = arrSize / numThreads;  // 计算每个线程处理的元素数量
    for (int i = 0; i < numThreads; i++) {
        int start = i * step;
        int end = (i == numThreads - 1) ? arrSize : (start + step);
        threads[i] = std::thread(calculateSum, std::ref(arr), start, end, std::ref(partialSums[i]));
    }

    // 等待线程结束
    for (auto& thread : threads) {
        thread.join();
    }

    // 计算所有线程的和
    int totalSum = 0;
    for (int i = 0; i < numThreads; i++) {
        totalSum += partialSums[i];
    }

    std::cout << "数组元素的总和为:" << totalSum << std::endl;

    return 0;
}

代码解释:

  • calculateSum 函数中,每个线程计算数组的一个片段。该函数接受一个引用的数组、起始索引、结束索引和一个引用的变量 sum,并将计算的结果保存在 sum 中。
  • main 函数中,我们首先定义了一个包含数组元素的向量 arr,然后指定了要使用的线程数量 numThreads,以及数组的大小 arrSize
  • 创建了两个向量 threadspartialSums,分别用于存储线程对象和每个线程计算得到的和。
  • 根据线程数量 numThreads 和数组大小 arrSize,计算了每个线程要处理的元素数量 step
  • 使用 for 循环创建了 numThreads 个线程,并分别传递给它们不同的数组片段进行计算。注意,我们使用 std::ref 来传递引用类型的参数。
  • 使用另一个 for 循环等待所有线程执行完毕,通过调用 join() 方法来实现线程同步。
  • 最后,计算所有线程计算得到的和,保存在 totalSum 中,并输出结果。

这是一个简单的多线程例子,通过将数组分成多个片段,使用多个线程并行计算,并最后合并结果。请注意,在实际开发中,需要考虑线程之间的同步和共享数据的安全性,以避免竞争条件等问题。

以此记录自己的多线程学习之旅!

评论区欢迎留言,大家一起学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/910768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无涯教程-PHP - ereg()函数

ereg() - 语法 int ereg(string pattern, string originalstring, [array regs]); ereg()函数在string指定的字符串中搜索pattern指定的字符串&#xff0c;如果找到pattern&#xff0c;则返回true&#xff0c;否则返回false。搜索对于字母字符区分大小写。 可选的输入参数re…

拒绝摆烂!C语言练习打卡第五天

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;每日一练 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、选择题 &#x1f4dd;1.第一题 &#x1f4dd;2.第二题 &#x1f4d…

论文复现--关于yolov8在姿态估计方面的研究

分类&#xff1a;动作捕捉 github地址&#xff1a;https://github.com/ultralytics/ultralytics 所需环境&#xff1a; Windows10&#xff0c;CUDA11.6&#xff0c;conda 4.13.0&#xff0c;Visual Studio 2017&#xff1b; 目录 环境搭建Conda list使用测试 环境搭建 # 创建环…

企业出海营销:如何借助HubSpot将潜在用户引导为忠实客户

在全球化的商业环境中&#xff0c;企业出海营销已成为实现可持续增长的重要策略之一。然而&#xff0c;成功吸引潜在客户并将其转化为忠实客户并非易事。 这正是HubSpot这款强大的综合性平台发挥作用的时候&#xff0c;它不仅帮助企业引导潜在客户进入销售漏斗&#xff0c;还在…

PyQty5—第一课:安装及简单的界面设计(附代码)

在日常办公中我们将经常使用的代码与PyQty5进行配合&#xff0c;从而设计出GUI的小程序&#xff0c;这样不经界面好看而且可以进行打包&#xff0c;发给自己的亲朋好友们进行使用&#xff0c;那么今天我们就来进行PyQty5的第一节课 1、首先我们需要安装PyQty5的库 库名安装si…

Jmeter压测 —— 动态数据关联

在进行压测时&#xff0c;经常需要对一些动态的数据进行数据关联。要不然容易造成脚本回放失败&#xff0c;或者多个虚拟用户执行时&#xff0c;只有一个用户运行成功。如下图&#xff1a;未关联数据时&#xff0c;脚本参数及回放结果 因此&#xff0c;在进行压测时&#xff0c…

opencv 进阶15-检测DoG特征并提取SIFT描述符cv2.SIFT_create()

前面我们已经了解了Harris函数来进行角点检测&#xff0c;因为角点的特性&#xff0c;这些角点在图像旋转的时候也可以被检测到。但是&#xff0c;如果我们放大或缩小图像时&#xff0c;就可能会丢失图像的某些部分&#xff0c;甚至有可能增加角点的质量。这种损失的现象需要一…

纯js封装一个弹出窗口

先上效果图&#xff1a; 左图是默认的样式(默认标题是黑色的。不是橙色的。截图时我改了点东西所以变了色。。。)。右图是通过传递参数自定义了外观的样式。 封装实现&#xff1a; function showWindow() {this.rnd Math.random();this.obj null;this.title ;this.content …

NER(命名实体识别)的介绍与使用--附源码

概述 本文将向您简要介绍命名实体识别,这是一种用于识别文本文档中存在的实体的流行方法。本文针对 NLP 领域的初学者。在本文末尾,已经实现了预训练的 NER 模型来展示实际用例。 为什么是NER? 图1 通过观察上

排序算法之详解选择排序

引入 选择排序顾名思义是需要进行选择的&#xff0c;那么就要问题了&#xff0c;选择到底是选择什么呢?选择排序的选择是选择数组中未排序的数组中最小的值&#xff0c;将被选择的元素放在未排序数组的首位 如果你对 ‘未排序数组’ &#xff0c; ‘选择’ 的概念不理解&#…

C++中机器人应用程序的行为树(ROS2)

马库斯布赫霍尔茨 一、说明 以下文章为您提供了对机器人应用程序或框架中经常使用的行为树的一般直觉&#xff1a;ROS&#xff0c;Moveit和NAV2。了解行为 Tress &#xff08;BT&#xff09; 框架的原理为您提供了在游戏领域应用知识的绝佳机会。BT可以与Unity或Unreal集成。 由…

淘宝有哪些值得抓取的数据?通过API可以获取到哪些数据?

淘宝是中国最大的在线购物平台&#xff0c;有丰富的数据可供抓取。以下是一些值得抓取的数据以及通过API可以获取到的数据&#xff1a; 1. 商品信息&#xff1a;包括商品标题、价格、销量、评价等。 2. 店铺信息&#xff1a;包括店铺名称、店铺信用、开店时间等。 3. 物流信…

java测试抽红包接口概率《搬代码》

1.首先我们进行抽红包概率测试的时候&#xff0c;为了测试抽取红包的概率完全正确。个人建议不使用线程池多线程执行&#xff0c;建议直接使用for循环执行 2.我们调取抽红包接口返回的信息值进行判断 3.下面就是判断代码&#xff0c;然后是抽红包接口代码 Test public static …

探索智能文字识别:技术、应用与发展前景

探索智能文字识别&#xff1a;技术、应用与发展前景 前言一张图全览大赛作品解读随心记你不对我对小结 智能文字识别体系化解读图像预处理文字定位和分割文字区域识别图像校正字体识别和匹配结果后处理小结 如何应对复杂场景下挑战复杂场景应对方法小结 人才时代对人才要求合合…

源代码审计对企业有哪些好处?

源代码扫描 源代码扫描&#xff0c;对应用程序进行静态漏洞扫描&#xff0c;分析源代码中存在的安全风险&#xff0c;运行应用于模拟器中对应用进行实时漏洞攻击检测。 你是否了解源代码扫描对企业的好处&#xff1f; 一、源代码扫描&#xff0c;通常能够帮助企业解决这些问题…

docker 01(初识docker)

一、docker概念 Docker是一个开源的应用容器引擎&#xff1b;诞生于2013年初&#xff0c;基于Go 语言实现&#xff0c;dotCloud公司出品(后改名为Dockerlnc);Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux …

KCC@杭州-在初秋,来一场智力与体能的比拼

本次主题&#xff1a; 开源知识问答桌游/运动&#xff08;一场智力与体力的比拼&#xff09; KCC杭州活动又来啦&#xff01; 在这个如火的八月&#xff0c;我们将要开启KCC杭州的一场特色开源活动。 为了让活动更加有趣味&#xff0c;更加具有互动性&#xff0c;我们将采用知识…

QTreeWidget和QTreeWidgetItem

QTreeWidget介绍 QTreeWidget 是一个用于显示层次结构数据的 Qt 控件&#xff0c;它以树状结构的形式展示项目和子项。每个项目都可以包含子项&#xff0c;并且可以通过展开和折叠来浏览整个树。 QTreeWidget类是一个方便的类&#xff0c;它提供了一个带有经典基于项目的界面…

AI极客日报0822 - AI创作是否应该有版权?

&#x1f440;AI 日报合集 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 人工智能系统依法享有版权吗&#xff1f;这位法官给出了肯定的答案。让我们开始吧。 今日看点&#xff1a; 一位联邦法官明确表示&#xff0c;AI创作的艺术品没有版权&#xff01;中国&#xff0c…

WGS84地球坐标系,GCJ02火星坐标系,BD09百度坐标系简介与转换 资料收集

野火 ATGM332D简介 高性能、低功耗 GPS、北斗双模定位模块 STM32 GPS定位_为了维护世界和平_的博客-CSDN博客 秉火多功能调试助手上位机开源&#xff01;共六款软件&#xff0c;学到你吐... , - 电脑上位机 - 野火电子论坛 - Powered by Discuz! https://www.firebbs.cn/for…