并发编程实践:进程、线程和threading 模块的全面解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 并发编程实践:进程、线程和threading 模块的全面解析

前言


国庆假期回来上班第一天,日常犯困。


一、进程和线程的区别


1-1、进程


  • 进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程。是操作系统资源分配的基本单元。


6ae18169527e42538bd91ddfceb00869.png

1-2、线程

  • 线程进程中的一个执行单元,一个进程至少有一个线程,一个进程可以运行多个线程。是比进程更小的独立运行的基本单元,故也被成为轻量级进程。(协程是一种比线程更轻量级的存在,一个线程可以拥有多个协程。)


2f83e6e32c6c4fabbe2accf6a4eae12c.png


1-3、区别


  • 区别

1、根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位

2、资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

3、包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

4、内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。

5、影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

6、执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。


综上所述,进程和线程都有各自的优缺点,操作系统会根据应用程序的需求和系统资源的限制来选择合适的方式来实现多任务。


二、使用threading 模块来创建多线程


2-0、threading模块介绍


Python的 threading 模块提供了线程相关的类和方法,可以在 Python 程序中创建和控制多个线程,实现多任务并发执行。

该模块主要包含以下类和方法


  • Thread 类:表示一个线程,可以通过继承该类来创建自定义的线程类,并实现自己的 run 方法来定义线程的具体行为。
  • Lock 类:表示一个锁对象,用于控制多个线程对共享资源的访问。可以使用 acquire 和 release 方法来加锁和释放锁。
  • RLock 类:表示可重入锁对象,与 Lock 类类似,但可以在同一个线程中多次获取锁而不会导致死锁。
  • Condition 类:表示条件变量对象,用于在线程之间进行协调和同步,可以使用 wait、notify 和 notify_all 方法来等待和通知其他线程。
  • Event 类:表示事件对象,用于线程之间的通信和同步,可以使用 set 和 clear 方法来设置和清除事件状态,使用 wait 方法来等待事件触发。
  • Timer 类:表示定时器对象,用于在指定时间后触发一个函数,可以使用 start 和 cancel 方法来启动和取消定时器。


使用 threading 模块可以方便地创建和控制多个线程,实现并发执行的程序。但需要注意多线程编程可能存在的竞态条件、死锁等问题,需要合理使用锁、条件变量等同步机制来保证程序的正确性和稳定性。


2-1、使用threading.Thread()方法开启线程


使用 threading.Thread() 方法可以创建线程对象并启动线程。以下是详细的使用方法:

  • 创建 Thread 对象

创建 Thread 对象时,需要提供一个可调用对象(通常是一个函数)作为线程的执行函数。可以通过直接传递函数名或使用 lambda 表达式来创建可调用对象,使用threading.Thread()创建


启动线程


创建 Thread 对象后,可以通过调用start()方法启动线程。


等待线程结束


如果需要等待一个线程执行结束,可以使用)join()方法。join() 方法会阻塞当前线程,直到被调用的线程执行结束。


以下为案例分析

# 导入threading类
import threading
import time
def thread_job():
    print('T1 start\n')
    for i in range(10):
        time.sleep(0.1)
    print('T1 finish\n')
def T2_job():
    print('T2 start\n')
    print('T2 finish\n')
def main():
  # 每个Thread对象都代表一个线程。每个线程我们可以让程序处理不同的任务,这样就是多线程编程。
  # 将需要被调用的函数传递给参数target。
  # name: 线程的名字。
  # args=(): 使用args可以传入实参。
    added_thread = threading.Thread(target=thread_job, name='T1')
    thread2 = threading.Thread(target=T2_job, name='T2')
    # 调用start方法来让线程启动。
    added_thread.start()
    thread2.start()
    print('all done\n')
if __name__ == '__main__':
    main()


输出

T1 start

T2 start

all done

T2 finish

T1 finish

Tips:默认情况下,调用start方法使得线程开始后,并不需要等待该线程执行完毕就会往下执行,所以输出看起来没那么规则。


2-2、使用join()方法来阻塞进程

# 上边的代码几个线程是同时运行的,如果让一个先运行,一个后运行,应该怎么做呢?
import threading
import time
def thread_job():
    print('T1 start\n')
    for i in range(10):
        time.sleep(0.1)
    print('T1 finish\n')
def T2_job():
    print('T2 start\n')
    print('T2 finish\n')
def main():
    added_thread = threading.Thread(target=thread_job, name='T1')
    thread2 = threading.Thread(target=T2_job, name='T2')
    added_thread.start()
    # 调用join函数可以使得该线程结束后才会接着向下执行。
    added_thread.join()
    thread2.start()
    thread2.join()
    print('all done\n')
if __name__ == '__main__':
    main()

输出

T1 start

T1 finish

T2 start

T2 finish

all done

Tips:这样看起来规则了,但是这和不使用线程直接执行函数好像没什么区别了。


2-3、其他threading模块常用方法


  • threading.current_thread():
    返回当前线程对象。
  • threading.active_count():
    返回当前线程总数,包括主线程和所有子线程。
  • threading.enumerate():
    返回一个包含所有当前活动线程的列表。
  • threading.Lock():
    创建一个锁对象,可以用来保护共享资源,防止多个线程同时访问。
  • threading.RLock():
    创建一个可重入锁对象,可以被同一个线程多次获取锁,主要用于递归函数。
  • threading.Condition(lock=None):
    创建一个条件变量对象,可以用来实现多个线程之间的协作。
  • threading.Event():
    创建一个事件对象,可以用来实现线程间的同步。
  • threading.Timer(interval, function, args=[], kwargs={}):
    创建一个定时器对象,用于在指定时间后执行某个函数。


三、GIL锁

3-1、什么是GIL?


GIL即全局解释器锁,每个线程在执行时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU,也就是说多线程并不是真正意义上的同时执行。


3-2、通过threading.Lock()保证线程同步

目的:为了协调各个线程修改同一份数据。

创建锁:lock = threading.Lock()

锁定和释放:lock.acquire()和lock.release()


参考文章:

Python多线程库threading的使用.

进程和线程的区别(超详细).

Python多线程编程(一):threading 模块 Thread 类的用法详解.

Python 多线程编程(二):threading 模块中 Lock 类的用法详解.

Python多线程之threading.Thread()基本使用.


总结

Lock类这一块后续用的上的时候再研究吧,暂时还没用到,有需要的,看倒数第二篇参考文章噢。

相关文章
|
2月前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
271 30
|
2月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
194 14
|
2月前
|
存储 算法
深入解析PID控制算法:从理论到实践的完整指南
前言 大家好,今天我们介绍一下经典控制理论中的PID控制算法,并着重讲解该算法的编码实现,为实现后续的倒立摆样例内容做准备。 众所周知,掌握了 PID ,就相当于进入了控制工程的大门,也能为更高阶的控制理论学习打下基础。 在很多的自动化控制领域。都会遇到PID控制算法,这种算法具有很好的控制模式,可以让系统具有很好的鲁棒性。 基本介绍 PID 深入理解 (1)闭环控制系统:讲解 PID 之前,我们先解释什么是闭环控制系统。简单说就是一个有输入有输出的系统,输入能影响输出。一般情况下,人们也称输出为反馈,因此也叫闭环反馈控制系统。比如恒温水池,输入就是加热功率,输出就是水温度;比如冷库,
515 15
|
2月前
|
存储 缓存 Python
Python中的装饰器深度解析与实践
在Python的世界里,装饰器如同一位神秘的魔法师,它拥有改变函数行为的能力。本文将揭开装饰器的神秘面纱,通过直观的代码示例,引导你理解其工作原理,并掌握如何在实际项目中灵活运用这一强大的工具。从基础到进阶,我们将一起探索装饰器的魅力所在。
|
2月前
|
机器学习/深度学习 搜索推荐 API
淘宝/天猫按图搜索(拍立淘)API的深度解析与应用实践
在数字化时代,电商行业迅速发展,个性化、便捷性和高效性成为消费者新需求。淘宝/天猫推出的拍立淘API,利用图像识别技术,提供精准的购物搜索体验。本文深入探讨其原理、优势、应用场景及实现方法,助力电商技术和用户体验提升。
|
2月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
82 4
|
2月前
|
监控 搜索推荐 测试技术
电商API的测试与用途:深度解析与实践
在电子商务蓬勃发展的今天,电商API成为连接电商平台、商家、消费者和第三方开发者的重要桥梁。本文深入探讨了电商API的核心功能,包括订单管理、商品管理、用户管理、支付管理和物流管理,并介绍了有效的测试技巧,如理解API文档、设计测试用例、搭建测试环境、自动化测试、压力测试、安全性测试等。文章还详细阐述了电商API的多样化用途,如商品信息获取、订单管理自动化、用户数据管理、库存同步、物流跟踪、支付处理、促销活动管理、评价管理、数据报告和分析、扩展平台功能及跨境电商等,旨在为开发者和电商平台提供有益的参考。
96 0
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
131 2
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

推荐镜像

更多