「Python入门」Python多线程

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 1. **线程与进程区别**:线程共享内存,进程独立;线程启动快,多线程效率高于多进程。2. **多线程使用**:直接使用Thread类,通过`target`指定函数,`args`传递参数;或继承Thread,重写`run`方法。3. **守护线程**:设置`setDaemon(True)`,主线程结束时,守护线程一同结束。4. **join线程同步**:主线程等待子线程完成,如`t.join()`。5. **线程锁**(Mutex):防止数据竞争,确保同一时间只有一个线程访问共享资源。6. **RLock(递归锁)**:允许多次锁定,用于需要多次加锁的递归操作。

@TOC


前言

线程 也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
多线程 线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄和其他进程应有的状态。

  • 进程之间不能共享内存,但线程之间共享内存非常容易。
  • 操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此使用多线程来实现多任务并发执行比使用多进程的效率高。
  • python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。

在这里插入图片描述


一、线程与进程的区别

  • 线程共享内存,进程独立内存
  • 线程启动速度块,进程启动速度慢,运行时速度没有可比性
  • 同一个进程的线程间可以直接交流,两个进程想通信,必须通过一个中间代理来实现
  • 创建新线程很简单,创建新进程需要对其父进程进行一次克隆
  • 一个线程可以控制和操作同一线程里的其他线程,但是进程只能操作子进程

二、多线程的使用方式

2.1 直接使用

# 文件名 python1.py
# -*- coding:utf-8 -*-
# 线程直接使用
import threading
import time


# 需要多线程运行的函数
def fun(args):
    print("我是线程%s" % args)
    time.sleep(2)
    print("线程%s运行结束" % args)


# 创建线程
t1 = threading.Thread(target=fun, args=(1,))
t2 = threading.Thread(target=fun, args=(2,))
start_time = time.time()
t1.start()
t2.start()
end_time = time.time()
print("两个线程一共的运行时间为:", end_time-start_time)
print("主线程结束")

"""
执行 python python1.py
运行结果:
我是线程1
我是线程2两个线程一共的运行时间为: 0.0019996166229248047
主线程结束

线程1运行结束
线程2运行结束
"""
AI 代码解读

在这里插入图片描述

2.2 继承式调用

# 文件名 python2.py
# 继承式调用
import threading
import time


class MyThreading(threading.Thread):
    def __init__(self, name):
        super(MyThreading, self).__init__()
        self.name = name

    # 线程要运行的代码
    def run(self):
        print("我是线程%s" % self.name)
        time.sleep(2)
        print("线程%s运行结束" % self.name)


t1 = MyThreading(1)
t2 = MyThreading(2)
start_time = time.time()
t1.start()
t2.start()
end_time = time.time()
print("两个线程一共的运行时间为:", end_time-start_time)
print("主线程结束")

"""
执行 python python2.py
运行结果:
我是线程1
我是线程2
两个线程一共的运行时间为: 0.0010724067687988281
主线程结束
线程2运行结束
线程1运行结束
"""
AI 代码解读

在这里插入图片描述

三、 守护线程

  • 在Python多线程编程中,join方法的作用式线程同步。
  • 守护线程,是为守护别人而存在的,当设置为守护线程后,被守护的主线程不存在后,守护线程也自然不存在。

Python多线程默认情况(设置线程setDaemon(False)),主线程执行完自己的任务后,就退出了,此时子线程会继续执行自己的任务,直到子线程任务结束
代码演示:threading中的两个创建多线成的例子都是。

# 守护线程
import threading
import time


class MyThreading(threading.Thread):
    def __init__(self, name):
        super(MyThreading, self).__init__()
        self.name = name

    # 线程要运行的代码
    def run(self):
        print("我是线程%s" % self.name)
        time.sleep(2)
        print("线程%s运行结束" % self.name)


t1 = MyThreading(1)
t2 = MyThreading(2)
start_time = time.time()
t1.setDaemon(True)
t1.start()
t2.setDaemon(True)
t2.start()
end_time = time.time()
print("两个线程一共的运行时间为:", end_time-start_time)
print("主线程结束")
"""
执行 python python3.py
后续执行结果以截图的形式呈现,文件名可自定义为xx.py,执行 python xx.py 指令即可.
"""
AI 代码解读

在这里插入图片描述

四、 join线程同步

当不给程序设置守护进程时,主程序将一直等待子程序全部运行完成才结束

# join:线程同步
import threading
import time


class MyThreading(threading.Thread):
    def __init__(self, name):
        super(MyThreading, self).__init__()
        self.name = name

    # 线程要运行的代码
    def run(self):
        print("我是线程%s" % self.name)
        time.sleep(3)
        print("线程%s运行结束" % self.name)


threading_list = []
start_time = time.time()
for x in range(50):
    t = MyThreading(x)
    t.start()
    threading_list.append(t)

for x in threading_list:
    x.join()    # 为线程开启同步

end_time = time.time()
print("50个线程一共的运行时间为:", end_time-start_time)
print("主线程结束")
AI 代码解读

在这里插入图片描述

五、 线程锁(互斥锁Mutex)

一个进程下可以启用多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据。

# 线程锁(互斥锁Mutex)
# -*- coding:utf8  -*-
import threading
import time

num = 100
threading_list = []


def fun():
    global num
    print("get num:", num)
    num += 1
    time.sleep(1)


for x in range(200):
    t = threading.Thread(target=fun)
    t.start()
    threading_list.append(t)

for x in threading_list:
    x.join()

print("nun:", num)
AI 代码解读

在这里插入图片描述

六、 RLock(递归锁)

# RLock(递归锁)
import threading, time
def run1():
    lock.acquire()
    print("grab the first part data")
    global num
    num += 1
    lock.release()
    return num


def run2():
    lock.acquire()
    print("grab the second part data")
    global num2
    num2 += 1
    lock.release()
    return num2


def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res, res2)


if __name__ == '__main__':
    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(3):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)
AI 代码解读

注:在开发的过程中要注意有些操作默认都是 线程安全的(内部集成了锁的机制),我们在使用的时无需再通过锁再处理

# RLock(递归锁)
import threading

data_list = []

lock_object = threading.RLock()


def task():
    print("开始")
    for i in range(1000000):
        data_list.append(i)
    print(len(data_list))


for i in range(2):
    t = threading.Thread(target=task)
    t.start()
AI 代码解读

在这里插入图片描述

七、 线程池

线程不是开的越多越好,开的多了可能会导致系统的性能更低了。

# 线程池
import time
from concurrent.futures import ThreadPoolExecutor  # 并行期货,线程池执行者
"""
pool = ThreadPoolExecutor(100)
pool.submit(函数名,参数1,参数2,参数...)
"""


def task(video_url, num):
    print("开始执行任务", video_url, num)     # 开始执行任务 www.vitian-99.vip 3
    time.sleep(1)


# 创建线程池,最多维护10个线程
threadpool = ThreadPoolExecutor(10)
# 生成100网址,并放入列表
url_list = ["www.vitian-{}.vip".format(i) for i in range(100)]
for url in url_list:
    """
    在线程池中提交一个任务,线程池如果有空闲线程,则分配一个线程去执行,执行完毕后在将线程交还给线程池,
    如果没有空闲线程,则等待。注意在等待时,与主线程无关,主线程依然在继续执行。
    """
    threadpool.submit(task, url, 3)

print("等待线程池中的任务执行完毕中······")
threadpool.shutdown(True)   # 等待线程池中的任务执行完毕后,在继续执行
print("END")
AI 代码解读

在这里插入图片描述

# 线程池的回调
import time
import random
from concurrent.futures import ThreadPoolExecutor


def task(video_url):
    print("开始执行任务", video_url)
    time.sleep(1)
    return random.randint(0, 10)    # 将结果封装成一个Futuer对象,返回给线程池


def done(response):     # response就是futuer对象,也就是task的返回值分装的一个Futuer对象
    print("任务执行完后,回调的函数", response.result())    # 即Futuer.result():取出task的返回值


# 创建线程池
threadpool = ThreadPoolExecutor(10)
url_list = ["www.xxxx-{}.com".format(i) for i in range(5)]
for url in url_list:
    futuer = threadpool.submit(task, url)    # futuer是由task返回的一个Future对象,里面有记录task的返回值
    futuer.add_done_callback(done)           # 回调done函数,执行者依然是子线程

# 优点:可以做分工,例如:task专门下载,done专门将下载的数据写入本地文件。
AI 代码解读

在这里插入图片描述

目录
打赏
0
2
1
1
10
分享
相关文章
|
18天前
|
Python字符串格式化利器:f-strings入门指南
Python字符串格式化利器:f-strings入门指南
127 80
Python与MongoDB的亲密接触:从入门到实战的代码指南
本文详细介绍了Python与MongoDB结合使用的实战技巧,涵盖环境搭建、连接管理、CRUD操作、高级查询、索引优化、事务处理及性能调优等内容。通过15个代码片段,从基础到进阶逐步解析,帮助开发者掌握这对黄金组合的核心技能。内容包括文档结构设计、批量操作优化、聚合管道应用等实用场景,适合希望高效处理非结构化数据的开发者学习参考。
57 0
揭秘Python的__init__.py:从入门到精通的包管理艺术
__init__.py是Python包管理中的核心文件,既是包的身份标识,也是模块化设计的关键。本文从其历史演进、核心功能(如初始化、模块曝光控制和延迟加载)、高级应用场景(如兼容性适配、类型提示和插件架构)到最佳实践与常见陷阱,全面解析了__init__.py的作用与使用技巧。通过合理设计,开发者可构建优雅高效的包结构,助力Python代码质量提升。
168 10
Python入门修炼:开启你在大数据世界的第一个脚本
Python入门修炼:开启你在大数据世界的第一个脚本
108 6
Python创意爱心代码大全:从入门到高级的7种实现方式
本文分享了7种用Python实现爱心效果的方法,从简单的字符画到复杂的3D动画,涵盖多种技术和库。内容包括:基础字符爱心(一行代码实现)、Turtle动态绘图、Matplotlib数学函数绘图、3D旋转爱心、Pygame跳动动画、ASCII艺术终端显示以及Tkinter交互式GUI应用。每种方法各具特色,适合不同技术水平的读者学习和实践,是表达创意与心意的绝佳工具。
1258 0
Python 编程基础与实战:从入门到精通
本文介绍Python编程语言,涵盖基础语法、进阶特性及实战项目。从变量、数据类型、运算符、控制结构到函数、列表、字典等基础知识,再到列表推导式、生成器、装饰器和面向对象编程等高级特性,逐步深入。同时,通过简单计算器和Web爬虫两个实战项目,帮助读者掌握Python的应用技巧。最后,提供进一步学习资源,助你在Python编程领域不断进步。
Python爬虫实战:利用短效代理IP爬取京东母婴纸尿裤数据,多线程池并行处理方案详解
本文分享了一套结合青果网络短效代理IP和多线程池技术的电商数据爬取方案,针对京东母婴纸尿裤类目商品信息进行高效采集。通过动态代理IP规避访问限制,利用多线程提升抓取效率,同时确保数据采集的安全性和合法性。方案详细介绍了爬虫开发步骤、网页结构分析及代码实现,适用于大规模电商数据采集场景。
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
167 0
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问