python--实验14 并发编程(多线程)

知识点 

 

  • 1 并发编程

    • 1.1程序提速手段
    • 1.2多任务
      • 并发

        • 在一个CPU一段时间内交替去执行任务。在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”。

      • 并行

        • 对于多核CPU处理多任务,操作系统会给CPU的每个内核安排一个执行的软件,多个内核分别运行不同的程序。

    • 1.3进程
      • 进程定义

        • 一个正在运行的程序或者软件就是一个进程。每个进程都有自己独立的一块内存空间。

      • 静态--程序 动态--进程是“活着”的程序 地址空间、内存、数据栈、用于跟踪执行的辅助程序

    • 1.4线程
      • 线程定义

        • 线程是进程中执行代码的一个分支,是CPU调度和分派的基本单位,一个进程可以有一个或多个线程,各个线程之间共享进程的内存空间。程序中的线程在相同的内存空间中执行,并共享许多相同的资源。

      • 线程特点

    • 1.5python对并发编程的支持
      • 多线程

        • threading,利用CPU和IO可以同时执行的原理

      • 多进程

        • multiprocessing,利用多核CPU的能力,真正的并行执行任务。

      • 异步IO

        • asyncio,利用单线程CPU和IO可以同时执行的原理,实现函数异步执行。

      • 注意

        • 利用Lock对资源加锁,防止冲突访问。

        • 使用Queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式

        • 使用线程池Pool/进程池Pool,简化任务提交、等待结果、获取结果

        • 使用subprocess启动外部程序的进程,并进行输入输出交互

    • 1.6全局解释器锁GIL
      • 定义

      • I/O密集型计算采用多线程的方法

    • 1.7根据任务选择并发技术
  • 2 多进程

    • 2.1四种创建方式
      • os.fork()函数

      • multiprocessing模块Process类创建进程

        • Python的多进程包multiprocessing可以完成从单进程到并发执行的转换,支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Lock等组件。

        • 创建进程

          • Process类,该类可用来在Windows平台上创建新进程。

          • 直接创建Process类的实例对象

            • (1)导入进程包

            • (2)Process进程类的说明

          • 通过继承Process类的子类,创建实例对象。

          • 注意,继承Process类的子类需重写父类的run()方法。

      • Process子类创建进程

      • 进程池Pool类创建进程

        • 常用方法

    • 2.2进程间通信
      • 常用方法

        • 管道是双向通信,数据进程不安全,队列是管道加锁来实现的

      • queue类

  • 3 多线程

    • 线程

      • 进程相当于房子,有(地址空间、内存、数据栈等)浴室、厨房; 线程相当于房子里的居住者,可以使用浴室洗澡,厨房做饭等。

    • 3.1创建线程
      • threading模块

        • 概述

          • Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装。

          • Python标准库模块threading提供了与线程相关的操作:创建线程、启动线程、线程同步。

          • 通过创建threading.Thread对象实例,可以创建线程;调用Thread对象的start()方法,可启动线程。也可以创建Thread的派生类,重写run方法,然后创建其对象实例来创建线程。

        • 函数样式

        • 常用方法

        • 示例

      • 说明

    • 3.2线程加入join()
      • 语法

        • Thread对象.join()

      • 作用

        • 若采用 t.join(),即让包含代码的线程(tc,即当前线程)“加入”到另外一个线程(t)的尾部。在线程(t)执行完毕之前,线程(tc)不能执行。

      • 说明

        • 1. 线程不能加入自己,否则将导致Runtime Error,形成死锁。

          • 2. 线程不能加入未启动的线程,否则将导致Runtime Error。

      • 示例

    • 3.3自定义派生于Thread的对象
      • 定义

        • 通过声明Thread的派生类,创建一个子类,并重写对象的run方法,然后创建其对象实例,可创建线程。通过对象的start方法,可启动线程,并自动执行对象的run方法。

      • 注意

        • 子类的构造器一定要先调用基类的构造器

        • 直接将线程需要做的事写到run方法中

      • 示例

  • 4 锁

    • 4.1锁--线程安全
      • 定义

      • 两种状态

      • 两种模式

    • 线程安全示例

      • 背景

        • 创建工作线程,模拟银行现金帐户取款。多个线程同时执行取款操作时,如果不使用同步处理,会造成账户余额混乱;尝试使用同步锁对象Lock,以保证多个线程同时执行取款操作时,银行现金帐户取款的有效和一致。

      • 代码

  • 5 生产者-消费者模型

    • 5.1生产者和消费者模型
    • 5.2queue模块
      • 两种通信

      • 概念

        • 使用Python标准模块queue提供了适用于多线程编程的先进先出的数据结构(即队列),用来在生产者和消费者线程之间的信息传递。使用queue模块中的线程安全的队列,可以快捷实现生产者和消费者模型。

      • 主要方法

        • (1)Queue(maxsize=0):构造函数,构造指定大小的队列。默认不限定大小

        • (2)put(item, block=True, timeout=None):向队列中添加一个项。默认阻塞,即队列满的时候,程序阻塞等待

        • (3)get(block=True, timeout=None):从队列中拿出一个项。默认阻塞,即队列为空的时候,程序阻塞等待

      • 图示

    • 基于queue.Queue的生产者和消费者模型

  • 6 小结

    • 线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。

    • 通过创建threading.Thread对象实例,可以创建线程;调用Thread对象的start()方法,可启动线程。也可以创建Thread的派生类,重写run方法,然后创建其对象实例来创建线程。

    • Lock对象锁解决线程安全问题:acquire()获得锁;release() 释放锁

    • queue模块提供了线程之间的数据传递:put()添加元素;get()获取元素

实验

一、实验目的:

1. 掌握pycharm的使用

2. 掌握python的面向对象的程序设计概念

3. 掌握多线程的使用

4. 理解python多线程互斥锁

二、实验环境

本次实验需使用实验室提供的Windows主机环境+pycharm

三、实验内容

说明:基础题为必做题,提高题为选做题

1.(基础题)编写程序实现:创建T1、T2、T3三个线程,怎样保证线程的执行顺序为T2->T1->T3?

import time

import threading

class TestThread(threading.Thread):

    def __init__(self, thread_name):

        super(TestThread, self).__init__()

        self.thread_name = thread_name

    def run(self):

        time.sleep(2)

        print('Thread:%s\t开始执行' % self.thread_name)

if __name__ == "__main__":

# 编写代码

import time
import threadingclass TestThread(threading.Thread):def __init__(self, thread_name):super(TestThread, self).__init__()self.thread_name = thread_namedef run(self):time.sleep(2)print('Thread:%s\t开始执行' % self.thread_name)if __name__ == "__main__":t1 = TestThread("T1")t2 = TestThread("T2")t3 = TestThread("T3")t2.start()  # 首先启动T2t2.join()   # 等待T2执行完成t1.start()  # 然后启动T1t1.join()   # 等待T1执行完成t3.start()  # 最后启动T3t3.join()   # 等待T3执行完成

2. (基础题)将下列程序进行修改,要求每次运行结果输出样式为:(注:采用lock)

import threading,time
def job1():
    global A
    for i in range(10):
      A += 1
      print('job1',A)
def job2():
    global A
    for i in range(10):
        A += 10
        print('job2',A)
if __name__ =='__main__':
    A = 0
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

import threading
import timedef job1():global Alock.acquire()for i in range(10):A += 1print('job1', A)lock.release()def job2():global Alock.acquire()for i in range(10):A += 10print('job2', A)lock.release()if __name__ == '__main__':A = 0lock = threading.Lock()  # 创建锁对象t1 = threading.Thread(target=job1)t2 = threading.Thread(target=job2)t1.start()t2.start()t1.join()t2.join()

3.(提高题)编写程序实现:使用多线程实现一个模拟银行取钱的程序,要求:

  1. 使用全局变量作为余额;
  2. 存取钱时都只能有一个线程访问全局变量
  3. 取钱线程和存钱线程同时运行,每次存取随机数量的金额,直到取钱余额不足时则打印出相关信息,并结束程序。
import threading
import time
import randomclass BankAccount:def __init__(self, balance):self.balance = balanceself.lock = threading.Lock()def deposit(self, amount):with self.lock:time.sleep(random.random())  # 模拟处理时间self.balance += amountprint(f"存入{amount}元,当前余额:{self.balance}元")def withdraw(self, amount):with self.lock:time.sleep(random.random())  # 模拟处理时间if self.balance >= amount:self.balance -= amountprint(f"取出{amount}元,当前余额:{self.balance}元")else:print(f"余额不足,无法取出{amount}元")return Falsereturn Truedef deposit_thread(account):while True:amount = random.randint(100, 500)account.deposit(amount)def withdraw_thread(account):while True:amount = random.randint(50, 300)if not account.withdraw(amount):breakif __name__ == "__main__":account = BankAccount(1000)deposit_thread = threading.Thread(target=deposit_thread, args=(account,))withdraw_thread = threading.Thread(target=withdraw_thread, args=(account,))deposit_thread.start()withdraw_thread.start()deposit_thread.join()withdraw_thread.join()

 

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

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

相关文章

[论文笔记] CT数据配比方法论——1、Motivation

我正在写这方面的论文,感兴趣的可以和我一起讨论!!!!!! Motivation 1、探测原有模型的配比: 配比 与 ppl, loss, bpw, benchmark等指标 之间的关系。 2、效果稳定的配比:配比 与 模型效果 之间的规律。 Experiments 1、主语言(什么语言作为主语言,几种主语言?…

鸿蒙Navigation路由能力汇总

基本使用步骤: 1、新增配置文件router_map: 2、在moudle.json5中添加刚才新增的router_map配置: 3、使用方法: 属性汇总: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-compone…

Java线程池ThreadPoolExecutor原理、源码分析

目录 为什么要使用线程池? 线程池执行任务的具体流程是怎样的? 线程池的五种状态是如何流转的? 线程池中的线程是如何关闭的? 线程池为什么一定得是阻塞队列? 线程发生异常,会被移出线程池吗&#xff…

Python爬虫实战 | 爬取携程网景区评论|美食推荐|景点列表数据

本文采用Selenium库爬取携程网的景区评论。 携程接口接入 Selenium介绍 Selenium是一个Web的自动化测试工具,可以按指定的命令自动操作,如让浏览器加载页面、获取数据、页面截屏等。Selenium本身不自带浏览器,需要与第三方浏览器结合才能使…

基于springboot和mybatis的RealWorld后端项目实战二之实现tag接口

修改pom.xml 新增tag数据表 SET FOREIGN_KEY_CHECKS0;-- ---------------------------- -- Table structure for tags -- ---------------------------- DROP TABLE IF EXISTS tags; CREATE TABLE tags (id bigint(20) NOT NULL AUTO_INCREMENT,name varchar(255) NOT NULL,PR…

一文认识21世纪商贸物流新格局

在21世纪的全球化浪潮中,商贸物流作为连接生产与消费的重要纽带,其地位日益凸显。随着信息技术的飞速发展,特别是大数据、云计算、物联网等技术的广泛应用,现代物流已远远超越了传统意义上的货物运输与仓储,向着智能化…

前端Canvas入门——用canvas写五子棋?

前言 五子棋的实现其实不难,因为本身就是一个很小的游戏。 至于画线什么的,其实很简单,都是lineTo(),moveTo()就行了。 难的在于——怎么让棋子落入到指定的格子上,怎么判断连子胜利。 当然啦,这部分是…

基于STC8H4K64TL单片机的触摸功能调试

基于STC8H4K64TL单片机的触摸功能调试 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单片机管脚图(20个引脚)STC8H系列单片机管脚说明STC8H系列单片机I/O口STC8H系列单片机I…

关于Codigger之软件项目体检Software Project HealthCheck

为你的软件项目提供快速、可靠的体检 项目体检是Codigger推出的智能代码质量检查工具,可以系统地帮助您交付干净的代码。作为我们Codigger解决方案的重要元素 ,代码体检集成到您现有的工作流程中并检测代码中的问题,以帮助您对项目执行持续的…

django中日志模块logging的配置和使用

一、文件的配置 settings.py文件中添加LOGGING块的配置,配置如下 # 日志记录 LOGGING {"version": 1,"disable_existing_loggers": False, # 用于确定在应用新的日志配置时是否禁用之前配置的日志器# 格式器"formatters": {"v…

云监控(华为) | 实训学习day4(10)

SpringBoot增删改的细节研究 一、Spring boot增的安全性 1.开启数据库的事务 SpringBoot中Service层有事务(保证操作成功) 两个用户操作,同时增加同一条数据(用户名,密码一致) 验证内容,开启…

MySQL:基础操作(增删查改)

目录 一、库的操作 创建数据库 查看数据库 显示创建语句 修改数据库 删除数据库 备份和恢复 二、表的操作 创建表 查看表结构 修改表 删除表 三、表的增删查改 新增数据 插入否则更新 插入查询的结果 查找数据 为查询结果指定别名 结果去重 where 条件 结…

【Jmeter】记录一次Jmeter实战测试

Jmeter实战 1、需求2、实现2.1、新建线程组2.2、导入参数2.3、新建HTTP请求2.4、添加监听器2.5、结果 1、需求 查询某个接口在高并发场景下的响应时间(loadtime),需求需要响应在50ms以内,接下来用Jmeter测试一下 Jmeter安装见文章《Jemeter安装教程&am…

多层全连接神经网络(四)---简单的前向网络

神经网络神经元概念部分有需要会单独再讲 激活函数 1. Sigmoid Sigmoid 非线性激活函数的数学表达式是 σ(z) ,其图形如图 3.14所示。目前我们知道 Sigmoid 激活函数是将一个实数输入转化到 0~1 之间的输出,具体来说也就是将越大的负数转化到越靠近 0…

C/C++蓝屏整人代码

文章目录 📒程序效果 📒具体步骤 1.隐藏任务栏 2.调整cmd窗口大小 3.调整cmd窗口屏幕颜色 4.完整代码 📒代码详解 🚀欢迎互三👉:程序猿方梓燚 💎💎 🚀关注博主&a…

笔记 7 :linux 011 注释,函 bread () , get_hash_table () , find_buffer ()

(57)接着介绍另一个读盘块的函数 bread(): (58)因为 函数 get_blk()大量调用了其它函数,一版面列举不完,故对其调用的函数先行注释:ge…

鲁大师2024半年报电动车智能排行:九号继续霸榜,极核本田乘胜追击

鲁大师2024年半年报正式发布,本次季报包含电动车智能排行,测试的车型为市面上主流品牌的主流车型,共计30款,全部按照评测维度更广、更专业的鲁大师电动车智慧评测2.0进行评分,测试的成绩均来自于鲁大师智慧硬件实验室。…

口袋奇兵游戏攻略:云手机辅助战锤入侵策略指南!

在《口袋奇兵》中,战锤入侵是一个重要的游戏环节,了解如何有效地参与战锤入侵能够帮助玩家获取更多的资源和提升自己的战力。本文将详细介绍战锤入侵的策略和技巧,帮助玩家在战锤入侵活动中取得更好的成绩。除了找到强力的游戏辅助&#xff0…

粉尘传感器助力面粉厂安全生产

在面粉加工行业中,粉尘问题一直是一个不容忽视的难题。从原料的破碎、研磨到成品的包装,整个生产流程中都会伴随着大量的粉尘产生。这些粉尘不仅影响生产环境,更对工作人员的健康、设备的安全运行以及环境保护构成严重威胁。因此,…

食堂采购系统开发:从需求分析到上线实施的完整指南

本篇文章,笔者将详细介绍食堂采购系统从需求分析到上线实施的完整过程,旨在为开发团队和管理者提供一个系统化的指南。 一、需求分析 1.用户需求 常见的需求包括: -采购计划管理 -供应商管理 -库存管理 -成本控制 -报表生成 2.系统功…