Python开发—— 多线程开发

1. 了解线程

1.1 进程和线程

        进程是资源分配的最小单位。每个进程都有独立的地址空间,进程之间互不影响。操作系统会为每个进程分配独立的内存空间和其他资源,如文件描述符等。

        线程是CPU调度的最小单位。一个进程可以包含多个线程,这些线程共享该进程的资源(如内存),但每个线程都有自己的栈空间和程序计数器。线程之间切换开销较小,适合并发执行。

2. Thread:执行线程的对象

2.1 threading.Thread构造函数

        构造一个新的线程对象,其构造函数的参数如下:

        group: 目前始终为 `None`,用于将来实现线程组时使用。

        target: 指定线程启动时需要调用的可调用对象(函数或方法)。如果为 `None`,则什么也不调用。常用于指定线程要执行的任务。

        name: 指定线程的名称。如果为 `None`,则系统自动分配一个以 "Thread-N" 开头的名字。便于调试和管理。

        args: 传递给 `target` 函数的位置参数元组。用于传递参数给线程执行的函数。

        kwargs: 传递给 `target` 函数的关键字参数字典。用于传递参数给线程执行的函数。

        daemon: 指定线程是否为守护线程。守护线程会在主线程结束后自动结束,非守护线程则会阻止主线程的结束。守护线程常用于后台运行的任务,如日志记录器。 示例代码

import threading

def print_numbers(n):
    for i in range(n):
        print(f"Number: {i}")

# 创建线程
t = threading.Thread(target=print_numbers, args=(5,), name="NumberPrinter")
t.start()
t.join()
print("Thread has finished execution")

2.2 join()方法等待线程结束

        join() 方法用于阻塞当前线程,直到调用 `join()` 的线程执行完毕。常用于在主线程中等待其他子线程结束后再继续执行。 示例代码

import threading
import time

def delayed_print():
    time.sleep(2)
    print("Delayed print")

# 创建并启动线程
t = threading.Thread(target=delayed_print)
t.start()

print("Waiting for the thread to finish...")
t.join()
print("Thread has finished execution")

3. 线程同步

3.1 线程同步的概念

        线程同步用于协调多个线程对共享资源的访问,避免数据竞争和不一致性。当多个线程同时访问和修改共享资源时,可能会导致数据不一致,线程同步机制可以确保同一时间只有一个线程能够访问共享资源,从而保证数据的一致性。

3.2 锁的概念

        锁(Lock)是一种用于线程同步的原语,用于确保同一时间只有一个线程能访问某个特定资源。

4. Lock 和 RLock 对象

4.1 Lock:锁原语对象

        Lock` 是最简单的一种线程同步机制。它只有两个状态:locked 和 unlocked。当一个线程获取到锁时,锁的状态变为 locked,其他线程尝试获取该锁时会被阻塞,直到该锁被释放。

import threading

lock = threading.Lock()
shared_resource = 0

def increment():
    global shared_resource
    with lock:
        local_copy = shared_resource
        local_copy += 1
        shared_resource = local_copy
        print(f"Resource value: {shared_resource}")

threads = []
for i in range(5):
    t = threading.Thread(target=increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

4.2 RLock:可重入锁对象

        RLock(可重入锁)允许同一个线程多次获取同一个锁,每次获取锁后必须释放相同次数的锁。这样可以避免在同一线程内多次获取锁时发生死锁。 

import threading

rlock = threading.RLock()
shared_resource = 0

def increment():
    global shared_resource
    with rlock:
        with rlock:
            local_copy = shared_resource
            local_copy += 1
            shared_resource = local_copy
            print(f"Resource value: {shared_resource}")

threads = []
for i in range(5):
    t = threading.Thread(target=increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

4.3 Lock 和 RLock 的区别

        Lock: 一个线程如果多次获取同一个 `Lock`,会导致死锁。适用于简单的线程同步情况。

        RLock: 允许同一个线程多次获取锁,必须释放相同次数的锁。适用于复杂的线程同步情况,需要在同一线程内多次获取锁。

5. 死锁

5.1 死锁是什么

        死锁是一种情况,当两个或多个线程互相等待对方释放资源时,会导致所有线程都被无限期地阻塞。简单来说,死锁是线程在等待中无法继续执行的状态。 

import threading

lock1 = threading.Lock()
lock2 = threading.Lock()

def task1():
    with lock1:
        print("Task 1 acquired lock 1")
        with lock2:
            print("Task 1 acquired lock 2")

def task2():
    with lock2:
        print("Task 2 acquired lock 2")
        with lock1:
            print("Task 2 acquired lock 1")

thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

        这个示例中,如果task1拿到lock1后等待 lock2,同时 task2 拿到 lock2 后等待 lock1,就会发生死锁。

6. 线程的其他同步机制

        除了 `Lock` 和 `RLock`,Python `threading` 模块还提供了其他一些同步机制:

6.1 Semaphore:信号量

        信号量用于控制对共享资源的访问数量。它维护一个计数器,每次 `acquire` 时减少计数器,每次 `release` 时增加计数器。计数器不能小于零,当计数器为零时,试图 `acquire` 的线程会被阻塞。 示例代码

import threading
import time

semaphore = threading.Semaphore(3)

def access_resource():
    with semaphore:
        print(f"Resource accessed by {threading.current_thread().name}")
        time.sleep(1)

threads = []
for i in range(10):
    t = threading.Thread(target=access_resource, name=f"Thread-{i+1}")
    threads.append(t)
    t.start()

for t in threads:
    t.join()

6.2 Event:事件对象

        事件对象用于线程间通信。一个线程等待事件发生,另一个线程触发事件。事件对象有一个内部标志,初始值为 `False`。当调用 `set()` 方法时,内部标志变为 `True`,所有等待该事件的线程被唤醒。当调用 `clear()` 方法时,内部标志变为 `False`。 

import threading
import time

event = threading.Event()

def wait_for_event():
    print(f"{threading.current_thread().name} waiting for event")
    event.wait()
    print(f"{threading.current_thread().name} event triggered")

def trigger_event():
    time.sleep(2)
    print("Event will be triggered")
    event.set()

threads = [threading.Thread(target=wait_for_event, name=f"Thread-{i+1}") for i in range(5)]
for t in threads:
    t.start()

trigger_thread = threading.Thread(target=trigger_event)
trigger_thread.start()

for t in threads:
    t.join()
trigger_thread.join()

6.3 Condition:条件变量

        条件变量允许线程在满足特定条件时被唤醒。它通常与锁(Lock 或 RLock)一起使用,用于复杂的线程间同步问题。 

import threading
import time

condition = threading.Condition()
shared_resource = []

def producer():
    global shared_resource
    while True:
        with condition:
            if len(shared_resource) < 5:
                item = len(shared_resource) + 1
                shared_resource.append(item)
                print(f"Produced item {item}")
                condition.notify_all()
            time.sleep(1)

def consumer():
    global shared_resource
    while True:
        with condition:
            while not shared_resource:
                condition.wait()
            item = shared_resource.pop(0)


            print(f"Consumed item {item}")
        time.sleep(1)

producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

producer_thread.start()
consumer_thread.start()

producer_thread.join()
consumer_thread.join()

        这些同步机制可以帮助你更好地管理多线程程序中的资源访问,确保数据一致性和线程安全。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VulnHub靶场之DarkHole_1

1 信息收集 1.1 主机发现 arp-scan -l 主机IP地址为&#xff1a;192.168.1.17 1.2 端口和服务扫描 nmap -sS -sV -A -T5 -p- 192.168.1.17 开放22&#xff0c;80端口 1.3 目录扫描 dirsearch -u 192.168.1.17 2 渗透 2.1 访问端口 2.2 注册账号 暴力破解不现实&#…

网口串口(Serialport)服务器

文章所用工具http://t.csdnimg.cn/2gIR8http://t.csdnimg.cn/2gIR8 搭建服务器界面 操作配置文件保存方式类 public string FileName { get; set; }public IniHelper(string name) {this.FileName name; //在构造函数中给路径赋值} 1 先导入c语言进行读取操作ini文件的方法 …

理解Netty的核心概念

一、理解Netty Netty是一个用于开发高性能网络应用的框架。为了更容易理解它&#xff0c;下面一些描述&#xff0c;不一定准确&#xff0c;但一定容易理解。 从Netty的Channel开始&#xff0c;把Netty所有的核心概念都串起来。 Channel 简单理解为一个连接。 有一个特殊的C…

python使用pywebview集成vue3和element-plus开发桌面系统框架

随着web技术越来越成熟&#xff0c;就连QQ的windows客户端都用web技术来开发&#xff0c;所以在未来&#xff0c;web技术来开发windows桌面软件也会越来越多&#xff0c;所以在此发展驱动之下&#xff0c;将最近流程的python与web技术相结合&#xff0c;使用vue3和element-plus…

使用requests爬取拉勾网python职位数据

爬虫目的 本文是想通过爬取拉勾网Python相关岗位数据&#xff0c;简单梳理Requests和xpath的使用方法。 代码部分并没有做封装&#xff0c;数据请求也比较简单&#xff0c;所以该项目只是为了熟悉requests爬虫的基本原理&#xff0c;无法用于稳定的爬虫项目。 爬虫工具 这次…

Linux中为什么etc是存放配置文件

在计算机系统中&#xff0c;/etc 是一个目录的名称&#xff0c;通常位于Unix和类Unix操作系统中&#xff0c;如Linux。这个目录用于存放系统配置文件。/etc 的命名来源于早期Unix系统中的 "etcetera"&#xff08;拉丁语 "et cetera" 的缩写&#xff0c;意为…

电子工程与网络技术解析

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 1、MUX&PD是什么意思 2、Hub 和HUB有什么区别 3、Redriver什么意思 4、Switch是什么意思 5、USB 2.0 ETHERNET2什么意思 6、…

[译]全栈Redux实战

本文乱译自一篇英文博文&#xff08;Full-Stack Redux Tutorial&#xff09;&#xff0c;本人英语能力不足&#xff0c;技术能力有限&#xff0c;如有错误&#xff0c;多多包涵。 #关于ReduxReactImmutable的测试先行开发综合指南 Redux是最近发生在js界令人兴奋的事儿。它把…

Vue+Xterm.js+WebSocket+JSch实现Web Shell终端

一、需求 在系统中使用Web Shell连接集群的登录节点 二、实现 前端使用Vue&#xff0c;WebSocket实现前后端通信&#xff0c;后端使用JSch ssh通讯包。 1. 前端核心代码 <template><div class"shell-container"><div id"shell"/>&l…

Unity动画系统(2)

6.1 动画系统基础2-3_哔哩哔哩_bilibili p316 模型添加Animator组件 动画控制器 AnimatorController AnimatorController 可以通过代码控制动画速度 建立动画间的联系 bool值的设定 trigger p318 trigger点击的时候触发&#xff0c;如喊叫&#xff0c;开枪及换子弹等&#x…

css flex 子元素溢出时,父元素被撑开解决方案

当父元素使用flex: 1;自适应填满时&#xff0c;子元素内容溢出&#xff0c;父元素内容撑大&#xff0c;导致页面显示问题&#xff0c;或设置了overflow 为scroll 的元素没出现滚动条等问题 解决方案&#xff1a; 1.如果是横向排列&#xff0c;flex: 1;的元素加上width: 0; 此…

【PB案例学习笔记】-28制作一个右键菜单

写在前面 这是PB案例学习笔记系列文章的第28篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

流量控制组件选型之 Sentinel vs Hystrix

Sentinel: Sentinel 是阿里中间件团队研发的面向分布式服务架构的轻量级高可用流量控制组件&#xff0c;于2018年7月正式开源。Sentinel 主要以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来帮助用户提升服务的稳定性。大家可能会问&#xff1a;Sen…

总线局域网及解决冲突的方案

上文内容&#xff1a;局域网 1.什么是总线局域网 总线网结构&#xff1a; 所有的结点通过专门的网卡附接到一条总线上&#xff1b; 所有结点的信息都发送到同一条总线上&#xff08;冲突&#xff09;&#xff1b; 所有结点都从同一媒体上收取信息&#xff08;广播&am…

视频汇聚/安防监控/GB28181国标EasyCVR视频综合管理平台出现串流的原因排查及解决

安防视频监控系统/视频汇聚EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;视频汇聚EasyCVR平台支持设备…

Stable Diffusion web UI 插件

2024.7.3更新&#xff0c;持续更新中 如果需要在linux上自己安装sd&#xff0c;参考&#xff1a;stable diffusion linux安装 插件复制到 /stable-diffusion-webui/extensions 目录下&#xff0c;然后重新启动sd即可 一、插件安装方法 每种插件的安装方法可能略有不同&#xf…

Redis分布式锁的应用场景有哪些

⼀ 、应⽤场景 在多线程并发的场景下 &#xff0c;Java Synchronized/Reentrantlock 锁能够实现同⼀个JVM进程内多线程 并发的安全性 &#xff0c;但⽆法保证多个JVM进程实例构成的集群环境在多线程下的安全性。在⼀些业务场景 下需要引⼊分布式锁。 1、缓存击穿 当某个热点缓…

精确计算应用的冷启动耗时

在iOS项目中&#xff0c;冷启动时间是指从用户点击应用图标开始&#xff0c;到应用完全加载并呈现出第一个界面&#xff08;可能需要网络请求必要的数据&#xff09;所花费的时间。这里以 main 函数为界&#xff0c;分为两个时间段&#xff1a; 从用户点击应用图标 ~ invoke m…

深度学习简介-AI(三)

深度学习简介 深度学习简介深度学习例子深度学习训练优化1.随机初始化2.优化损失函数3.优化器选择4.选择/调整模型结构 深度学习常见概念隐含层/中间层随机初始化损失函数导数与梯度优化器Mini Batch/epoch 深度学习训练逻辑图 深度学习简介 深度学习例子 猜数字 A: 我现在心…

24年河南特岗教师招聘流程+报名流程

河南特岗教师报名流程如下 1.登录河南省特岗招聘网 登录河南省特岗招聘网注册账号和密码&#xff0c;账号可以是手机号或者身份证号&#xff0c;密码自己设置 2.注册登录账号 注册完账号重新登录账号&#xff0c;输入身份证号、手机号、密码、验证码 3.浏览考试须知 填写个人信…
最新文章