Python之threading: 带你了解多线程的强大威力!

news2024/11/17 16:27:26

前言

什么是多线程

多线程是指在一个程序中同时创建和使用多个执行流(thread)来执行不同的任务。这样多个任务就可以同时进行,从而提高程序的执行效率。


在python使用多线程的方法

在 Python 中有两种方法可以使用多线程:使用 Python 自带的 threading 模块,或使用第三方库 multiprocessing

多线程的优势

多线程的好处在于可以利用多核 CPU 的优势,让程序在等待 I/O 操作时使用其他 CPU 核心,从而提高程序的效率。不过由于 Python 的全局解释器锁(Global Interpreter Lock, 简称GIL)的存在,在 Python 中创建的线程并不能真正并行执行。如果你需要在 Python 中创建多个真正并行的线程,可以使用 multiprocessing 库。


线程的安全问题

在使用多线程时,需要注意线程安全问题。如果多个线程同时访问同一个变量,可能会导致数据不一致的问题。为了解决这个问题,可以使用 threading 模块中的锁(Lock)和条件变量(Condition)来控制线程同步

使用锁的方式可以保证线程安全,但是会导致线程的执行效率降低。因此在使用多线程时,需要谨慎考虑是否真的需要使用多线程


threading模块常用方法

threading模块函数描述
threading.Thread(target=func, args=tuple, kwargs=dict)使用给定的参数创建一个新的 Thread对象
threading.active_count()返回当前活动的线程数
threading.current_thread()返回当前所使用的线程
threading.main_thread()返回主线程
threading.get_ident()返回线程标识符
threading.enumerate()返回当前活动的所有线程的列表
threading.BoundedSemaphore(num)控制线程同时执行的数量
Thread对象函数描述
start()启动线程
join([timeout])等待线程结束,如果提供了超时参数,则在超时后退出
is_alive()判断线程是否运行
setName(name)设置线程的名称
getName()获取线程名称

threading模块常用操作

1.创建线程

首先,我们需要创建一个 Thread 类的实例,并将要执行的函数作为参数传递给该实例。例如:

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function)

可以使用 Thread 类的 daemon 属性来设置线程为守护线程。守护线程是一种特殊的线程,它在主线程结束时会自动结束

要将线程设置为守护线程,只需将其 daemon 属性设置为 True

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function, name="MyThread", daemon=True)

2.启动线程

接下来,可以使用 thread.start() 方法来启动新线程,运行 my_function 函数。

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function)
thread.start()

3.等待线程结束

如果要等待所有线程完成,可以使用 thread.join() 方法。例如:

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function)
thread.start()
thread.join()

4.判断线程是否运行

使用 is_alive() 方法可以检查线程是否在运行

在下面例子中,我们调用了线程的 is_alive() 方法来检查它是否在运行。如果线程仍在运行,则会输出 “Thread is still running.”,否则会输出 “Thread is not running.”

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function)
thread.start()
if thread.is_alive():
    print("Thread is still running.")
else:
    print("Thread is not running.")

5.设置和获取线程名称

可以使用 Thread 类的 setName()getName() 方法来设置和获取线程的名称

import threading

def my_function():
    print("Hello from a new thread!")

thread = threading.Thread(target=my_function)
thread.setName("MyThread")
print(thread.getName())

6.查看当前活动线程数

使用 Python 的内置函数 threading.active_count() 来查看当前活动的线程数

import threading

def my_function():
    print("Hello from a new thread!")

thread1 = threading.Thread(target=my_function)
thread2 = threading.Thread(target=my_function)

thread1.start()
thread2.start()

print(threading.active_count())  #输出2

7.枚举当前活动线程

使用 threading.enumerate() 函数来枚举所有当前活动的线程

import threading

def my_function():
    print("Hello from a new thread!")

thread1 = threading.Thread(target=my_function)
thread2 = threading.Thread(target=my_function)

thread1.start()
thread2.start()

threads = threading.enumerate()
for thread in threads:
    print(thread.getName())

多线程实现共享资源访问

设置线程执行的先后顺序

1.使用join()

首先举个没有使用join()函数的线程例子, 在下述代码的输出可知, 线程的执行是并发的(一起执行的), 并没有明确要求先执行完work1线程后再执行work2线程

import threading
import time
def work1():
    for i in range(4):
        time.sleep(0.5)
        print("work1")

def work2():
    for i in range(4):
        time.sleep(0.5)
        print("work2")

def main():
    thread_add1 = threading.Thread(target=work1)
    thread_add1.start()
    thread_add2 = threading.Thread(target=work2)
    thread_add2.start()
main()

img


下面是使用了join()方法的代码, 从输出结果上看, 可以发现程序先等work1线程执行完后才能执行work2线程

import threading
import time
def work1():
    for i in range(4):
        time.sleep(0.5)
        print("work1")

def work2():
    for i in range(4):
        time.sleep(0.5)
        print("work2")

def main():
    thread_add1 = threading.Thread(target=work1,name="work1") #name参数:给线程命名
    thread_add1.start()
    thread_add1.join()
    thread_add2 = threading.Thread(target=work2,name="work2")
    thread_add2.start()
main()

img


2.使用threading.Lock()

当多个线程试图访问同一个资源时,可能会发生资源竞争。为了避免这种情况,您可以使用 lock() 方法来锁定资源,并在访问完成后解锁

在下面的代码中, 我们使用 lock.acquire() 方法锁定资源,然后使用 lock.release() 方法在访问完成后解锁。这样只有一个线程可以访问资源,其他线程必须等待

import threading
import time
lock = threading.Lock()
def work1():
    lock.acquire()
    for i in range(4):
        time.sleep(0.5)
        print("work1")
    lock.release()

def work2():
    lock.acquire()
    for i in range(4):
        time.sleep(0.5)
        print("work2")
    lock.release()

def main():
    thread_add1 = threading.Thread(target=work1,name="work1") #name参数:给线程命名
    thread_add1.start()
    thread_add2 = threading.Thread(target=work2,name="work2")
    thread_add2.start()


main()

img


3.使用with函数

利用with函数你就可以不写上锁解锁这两行代码了,和文件打开和关闭差不多

import threading
import time
lock = threading.Lock()
def work1():
    with lock:
        for i in range(4):
            time.sleep(0.5)
            print("work1")


def work2():
    with lock:
        for i in range(4):
            time.sleep(0.5)
            print("work2")


def main():
    thread_add1 = threading.Thread(target=work1,name="work1") #name参数:给线程命名
    thread_add1.start()
    thread_add2 = threading.Thread(target=work2,name="work2")
    thread_add2.start()

main()

image-20221217154826309


控制线程同时执行的数量

使用threading.BoundedSemaphore()方法来控制线程同时执行的数量

import threading
import os
import time
semaphore = threading.BoundedSemaphore(5) #设置只能允许5个线程同时进行

def work1(se):
    se.acquire()
    print("test")
    se.release()

def main():
    for i in range(1,15):
        thread = threading.Thread(target=work1,args=(semaphore,)) #这里要注意,args参数需传递一个元组
        thread.start()
main()

注意

  • 使用threading模块的python文件名称不能取"threading", 否则导入threading模块时会报错, 例如: module 'threading' has no attribute '_shutdown'

  • 一旦线程启动,就不能重新启动。如果需要重新启动线程,则必须创建一个新的线程

  • 在使用线程时,需要注意资源竞争。在多线程环境中,各个线程可能会竞争共享资源,因此需要使用适当的同步机制来避免冲突

  • 线程是不能被强制终止的,因此您必须在线程中提供一个退出机制

  • 守护线程在后台运行,不会阻止程序的退出。如果您希望在线程中的任务执行完成后再退出程序,则不应使用守护线程

总结

总结一下,在 Python 中使用多线程的方法如下:

  1. 导入 threading 模块。
  2. 创建一个 Thread 类的实例,并将要执行的函数作为参数传递给该实例。
  3. 调用 thread.start() 方法启动新线程。
  4. 调用 thread.join() 方法等待所有线程完成。

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

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

相关文章

Redis Java 客户端工具 - Lettuce框架介绍

Redis Java 客户端 - Lettuce 今天学习下Redis Java客户端开源项目 - Lettuce&#xff0c;Lettuce支持同步、异步通信的方式 API调用&#xff0c;也支持响应式编程API&#xff0c;包括发布/订阅消息、高可用性服务部署架构。 开始之旅 Maven依赖 <dependency><gro…

Python实现SSH远程操作Linux(paramiko库)

参考&#xff1a;https://blog.csdn.net/qq_40558166/article/details/100172501 一、官网 https://www.paramiko.org/ 二、安装库 1.命令 pip install paramiko 或 pip install paramiko –i https://pypi.douban.com/simple/ 三、辅助软件(可忽略) 1.Xshell(执行命令) …

[附源码]Node.js计算机毕业设计黑格伯爵国际英语贵族学校官网Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Ubuntu 配置本地root登录

Ubuntu 配置本地root登录–18.04 给root用户设置密码 按照下图方式 命令&#xff1a;sudo passwd root 切换到root用户 使用 su 或者是 su root 切换到 root 修改配置文件 进入该目录&#xff1a; cd /usr/share/lightdm/lightdm.conf.d/ 查看文件 ls 使用gedit 编辑文…

Arduino UNO新手零基础入门学习博客汇总

写在开头 最近在上Arduino的课&#xff0c;可以说Arduino对新手来说非常友好了&#xff0c;因为相比于51和32&#xff0c;Arduino的库函数下载就好&#xff0c;不需要自己去写&#xff0c;就很方便 我的硬件设备 博客汇总 博客内容大多数以实际案例为主&#xff0c;基本都是…

机器学习100天(七):007 简单线性回归理论

机器学习100天,今天讲的是简单线性回归理论。 首先来看第一个问题:什么是线性回归?我们先引入一个例子。 假如我现在有一份数据,这份数据是一些地区人口和对应房价的信息。我们把这份数据展示在二维平面上。横坐标是人口,纵坐标是房价,红色的点就表示每个地区的实际人口…

论文精读:EfficientDet: Scalable and Efficient Object Detection

Abstract 首先&#xff0c;本篇论文提出了一种加权双向特征金字塔网络&#xff08;BiFPN&#xff09;&#xff0c;进行简单、快速的多尺度特征融合&#xff1b;其次&#xff0c;作者提出了一种复合尺度方法&#xff0c;同时统一调整所有主干、特征网络和box/类别预测网络的分辨…

kali linux的安装教程

kali linux的安装教程 在网上输入网址https://www.kali.org/get-kali/#kali-virtual-machines。 向下滚动鼠标滑轮选择如下图所示的图标进行安装iso镜像文件。 我们打开虚拟机&#xff0c;选择创建新的虚拟机 选择其中的自定义&#xff0c;随即点击下一步 点击下一步 点击下一步…

uboot通过bootargs传递内核中的模块传递参数

前言 bootargs是uboot向内核传递参数时使用的&#xff0c;本次我们要验证的是bootargs向内核启动后加载的模块传递的参数&#xff0c;真正的跨过山和大海。跟着我的脚步&#xff0c;来一次bootargs之旅。 这是一个综合性&#xff0c;系统性很强的实例验证&#xff0c;要做这个…

模式识别-期末复习题(问题集锦)

1.什么是模式&#xff1f;监督模式识别和非监督模式识别的典型过程分别是什么&#xff1f; 模式&#xff1a;指需要识别且可测量的对象的描述 监督模式识别&#xff1a;分析问题→原始特征提取→特征提取与选择→分类器设计 非监督模式识别&#xff1a;分析问题→原始特征提…

C++ Reference: Standard C++ Library reference: Containers: map: map: insert

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/insert/ 公有成员函数 <map> std::map::insert C98 single element (1) pair<iterator,bool> insert (const value_type& val); with hint (2) iterator insert (iterator positio…

【密码学】MD5、UUID,加盐,JWT的理解与使用范例

文章目录MD5加密&#xff1a;1、MD5加密安全访问认证示例代码&#xff1a;2、UUID简介&#xff1a;使用&#xff1a;3、加盐原理&#xff1a;示例代码&#xff1a;4、jwt认知&#xff1a;JWT 结构&#xff1a;范例代码&#xff1a;MD5加密&#xff1a; 1、MD5加密 Message Di…

计算机毕业设计springboot+vue基本微信小程序的疫情防控平台系统

项目介绍 当今社会疫情防控平台是必不可少的,大家都在听从政府的号召在居家隔离,不管是在城市还是在乡镇、农村,这引起我的注目,设计一套社区疫情防控系统,疫情防控需要大家共同努力、团结对社区居民进行了新型冠状病毒肺炎防控知识普及和宣传教育。针对这一需求,本文设计并实现…

LVS详细介绍,这么讲不信你不明白负载均衡

Linux virtual server&#xff0c;是一个基于集群技术和Linux操作系统&#xff0c;目的是实现一个高性能、高可用的服务器&#xff0c;主要工作在网络层。 他采取IP负载均衡&#xff0c;也叫三层负载均衡&#xff08;因为工作在OSI模型的第三层--网络层&#xff09;&#xff0…

java计算机毕业设计springboot+vue旅游攻略平台

项目介绍 目前,我国旅游业正处于高度发展的状态。越来越多的人在假日里选择出游作为放松自己身心的手段。随着网络的普及和发展,人们开始习惯性地在做某事之前先在网络上浏览相关的内容。旅游网站能够帮助游客了解景点相关信息,推出相应的线路信息供游客们选择,并查看相应的旅…

计算机网络实验——路由器的配置静态与RIP配置

前言 由于几个资料和老师给的ppt说的都不清楚&#xff0c;自己也没想到什么很巧妙的归纳方法&#xff0c;写个总结记录一下。 想必静态路由配置的过程中唯一的难点就是ip route这个指令&#xff0c;其他的什么添加接口&#xff0c;设置ip啥的都是基础路由配置中的内容&#xf…

2023春招面试专题:JAVA基础高频面试

ArrayList和LinkedList有哪些区别 ArrayList扩容机制: ArrayList() 会使用长度为零的数组ArrayList(int initialCapacity) 会使用指定容量的数组public ArrayList(Collection<? extends E> c) 会使用 c 的大小作为数组容量add(Object o) 首次扩容为 10&#xff0c;再次…

3D激光里程计其一:ICP

这里写目录标题1. ICP 整体流程2. ICP 的数学表示3. 基于 SVD 的 ICP3.1 旋转部分求解3.2 平移部分求解4. 基于优化的 ICP5. ICP 系列汇总Reference: 深蓝学院-多传感器融合 1. ICP 整体流程 目的&#xff1a;有两个相似的刚体点云&#xff0c;它们之间没有做好配准&#xff…

Golang原理分析:闭包及for range延迟绑定问题原理及解决

1.Golang中的闭包 1.1.什么是闭包 当一个函数引用了环境的变量&#xff0c;被引用的变量与该函数同时存在组成的系统&#xff0c;被称为闭包。 闭包 环境的变量 函数。 以下JavaScript代码展示了一个基础的闭包&#xff1a; name是init函数中的内部变量displayName()是i…

机器学习 鸢尾花(Iris Flower)数据集分析

目录 一&#xff1a;加载数据 二&#xff1a;提取特征数据 三&#xff1a;提取标签数据 四&#xff1a;数据划分 一&#xff1a;加载数据 加载数据&#xff0c;查看数据特征 from sklearn.datasets import load_iris# 1 加载数据 鸢尾花load_iris iris_datasets load_iri…