6. 初识多线程编程

news2024/11/26 10:22:58

1. 多线程

多线程非常重要,工作中用到的也是非常多,面试时也100%会问多线程。
关于多线程的相关知识,可以参考《计算机操作系统(第四版)》,或者自行百度查看有关文章以及视频都可以,此处不再赘述。

在这里插入图片描述

2. python中的多线程

2.1 多线程优点
多线程类似于同时执行多个不同程序,多线程运行有如下优点。
(1) 使用线程可以把占据长时间的程序中的任务放到后台去处理
(2) 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
(3) 程序的运行速度可能加快。
(4) 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

2.2 一些说明
(1) 线程隶属于进程
  每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
(2) 线程上下文
  每个线程都有他自己的一组CPU寄存器,称为线程上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
(3) 重要寄存器
  指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
2.3 python3中的线程
python3线程中常用的两个模块为:_threadthreading(推荐使用)。
thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 python3中不能再使用"thread" 模块。为了兼容性,python3将 thread 重命名为 "_thread"

3. _thread模块创建线程

调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下:

_thread.start_new_thread ( function, args[, kwargs] )

参数说明:
function - 线程函数
args - 传递给线程函数的参数,必须是个tuple类型
kwargs - 可选参数

# demo
import _thread

def print_count(threadname):
    count = 0
    while count < 100:
        count += 1
        print("%s: %d" % (threadname, count))

try:
    _thread.start_new_thread(print_count, ("线程1",))  # ("线程1", )为传递给print_time()的参数
    _thread.start_new_thread(print_count, ("线程2",))  # 注意, 因为参数是tuple类型, 所以传递一个参数时, 不要忘记逗号
except:
    print("Error: 无法启动线程")

while True: pass

在这里插入图片描述

4. threading模块创建线程

4.1 两种方式
python 的 threading 模块中提供了类 Thread 用于实现多线程,用户有两种创建多线程的方式:
(1) 在线程构造函数中指定线程的入口函数。
(2) 自定义一个类,该类继承类 Thread,在自定义的类中实现 run 方法。
4.2 关键函数
主要介绍 Thread 相关的三个函数的功能。
[a]. 类 Thread 的构造函数

def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)

参数说明:
group: 线程组,目前还没有实现,在此处必须是 None
target: 线程的入口函数,线程从该函数开始执行
name: 线程名
args: 线程的入口函数的参数,以元组的形式传入
kwargs: 线程的入口函数的参数,以字典的形式传入
使用 Thread 构造一个新线程时,必须指定 target 和 args 两个参数,target 为线程的入口,args 为线程入口函数的参数。

[b]. 类 Thread 的 start 方法

def start(self)

在线程对象的构造函数中 target 指定了线程入口函数,args 指定了线程入口函数的参数。线程对象的 start 方法使新线程开始执行,执行函数 target(args)。
[c]. 类 Thread 的 join 方法

 def join(self, timeout=None)

调用线程对象的 start 方法后,新线程开始执行函数 target(args)。调用线程对象的 join 方法,将在调用join()的地方发生阻塞(主线程阻塞)等待新线程执行完毕
4.3 两种方式举例
(1) 在线程构造函数中指定线程的入口函数

import time
import threading


def Entry(name, begin, end):
    count = begin
    while count < end:
        count += 1
        print("%s: %d" % (name, count))


t1 = threading.Thread(target=Entry, args=('thread_1', 0, 100))
t2 = threading.Thread(target=Entry, args=('thread_2', 0, 100))

t1.start()
t2.start()
t1.join()   # 等待t1结束
t2.join()   # 等待t2结束

在这里插入图片描述
(2) 自定义类继承threading.Thread类,并实现run()

import threading


def PrintCount(name, counter):
    count = 0
    while count < counter:
        print("%s: %d" % (name, count))
        count += 1


class MyThread(threading.Thread):
    def __init__(self, name, counter):
        threading.Thread.__init__(self)
        self.name = name
        self.counter = counter

    def run(self):
        print("开始线程: " + self.name)
        PrintCount(self.name, self.counter)
        print("退出线程: " + self.name)
        print('')


t1 = MyThread("thread_1", 20)
t2 = MyThread("thread_2", 20)

# 首先开启线程1, 等待线程1执行完毕后, 再开启线程2
t1.start()
t1.join()   # 阻塞等待线程1执行完毕
t2.start()
t2.join()
print("退出主线程.")

在这里插入图片描述

5. 一个案例来看看多线程在速度上的提升

# demo1
# 我们依次计算三个循环,然后看看3个全部计算完毕后的耗时统计
from datetime import datetime


def total(begin, end):
    sum = 0
    for item in range(begin, end):
        sum += item
    return sum


time0 = datetime.now()

total(1, 10000000)
total(1, 10000000)
total(1, 10000000)

time1 = datetime.now()
time = time1 - time0
print(time.microseconds)  # 微秒

在这里插入图片描述


# demo2
# 好, 我们采用多线程的形式去看看
from datetime import datetime
import threading

def total(begin, end):
    sum = 0
    for item in range(begin, end):
        sum += item
    return sum


time0 = datetime.now()

t1 = threading.Thread(target=total, args=(1, 10000000))
t2 = threading.Thread(target=total, args=(1, 10000000))
t3 = threading.Thread(target=total, args=(1, 10000000))

t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()

time1 = datetime.now()
time = time1 - time0
print(time.microseconds)  # 微秒

在这里插入图片描述

相比普通方式下的402233微秒,采用多线程的方式总共耗时307763微秒,因此使用多线程加快了程序的执行速度。当然,这只是一个示例型的程序。

6. 获取线程的返回值

在继承 Thread 实现多线程的方式中,将线程的返回值保存在线程对象中使用一个成员变量保存线程的返回值。下面通过一个具体的例子,说明如何获取线程的返回值。

import threading


class MyThread(threading.Thread):
    def __init__(self, begin, end):
        threading.Thread.__init__(self)
        self.result = None
        self.begin = begin
        self.end = end

    def run(self):
        self.result = 0
        for i in range(self.begin, self.end):
            self.result += i


t0 = MyThread(1, 51)
t1 = MyThread(51, 101)
t0.start()
t1.start()
t0.join()
t1.join()
print(t0.result)    # 获取线程的执行结果
print(t1.result)
print(t0.result + t1.result)

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

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

相关文章

常用网址-2023整理

办公&效率人民币大写转换 人民币大写 人民币RMB数字转大写汉字工具我的账单 - 支付宝Bypass - 分流抢票Zen Flowchart - 在线流程图MindMaster - 在线思维导图【抠图】在线抠图软件_AI抠图证件照换底色-稿定设计Visio模板推荐与VisualNet图库转化语音转文字iconfont-阿里巴…

LeetCode动态规划经典题目(九):middle

学习目标&#xff1a; 进一步了解并掌握动态规划 学习内容&#xff1a; 4. LeetCode62. 不同路径https://leetcode.cn/problems/unique-paths/ 5. LeetCode63. 不同路径 IIhttps://leetcode.cn/problems/unique-paths-ii/ 6. LeetCode343. 整数拆分https://leetcode.cn/pro…

人工智能学习06--pytorch06--神经网络骨架nn.Module scipy下载 现有网络模型的使用及修改(VGG16)

神经网络骨架nn.Module 括号里nn.Module表示继承Module类init 初始化 调用父类初始化函数forward scipy下载 pip install scipy -i https://pypi.douban.com/simple/ 现有网络模型的使用及修改&#xff08;VGG16&#xff09; pretrained为True时需要下载&#xff0c;在ima…

1. Spring 基础入门

文章目录1. 初识 spring1.1 系统架构1.2 学习路线1.3 核心概念2. IoC 与 DI 入门案例&#xff08;xml版&#xff09;2.1 IoC&#xff08;控制反转&#xff09;2.2 DI&#xff08;依赖注入&#xff09;3. bean 配置3.1 bean 基础配置3.2 bean 别名配置3.3 bean 作用范围配置4. b…

file控件与input标签的属性type=“hidden“标签

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>file控件于与input标签的属性type"hidden"标签</title> </head> <body bgcolor"antiquewhite"> …

k8s中使用Deployment控制器实现升级、回滚、弹性伸缩

前置条件&#xff1a;linux机器已安装k8s集群基于yaml文件创建pod,本次创建pod使用的web.yaml如下apiVersion: apps/v1 kind: Deployment metadata:creationTimestamp: nulllabels:app: webname: web spec:replicas: 2selector:matchLabels:app: webstrategy: {}template:metad…

从零开始的数模(八)TOPSIS模型

一、概念 1.1评价方法概述 1.2概念 TOPSIS &#xff08;Technique for Order Preference by Similarity to an Ideal Solution &#xff09;模型中文叫做“逼近理想解排序方法”&#xff0c;是根据评价对象与理想化目标的接近程度进行排序的方法&#xff0c;是一种距离综合评…

SAP入门技术分享六:搜索帮助

搜索帮助1.概要&#xff08;1&#xff09;利用ABAP数据字典的搜索帮助&#xff08;2&#xff09;利用画面的搜索帮助&#xff08;3&#xff09;Dialog程序中的搜索帮助&#xff08;4&#xff09;报表选择屏幕PARAMETERS的搜索帮助&#xff08;5&#xff09;搜索帮助类型2.创建搜…

plot4gmns:面向通用建模网络范式(GMNS)的快速可视化【v0.1.1】

一款面向通用建模网络范式&#xff08;GMNS&#xff09;的快速可视化工具 目录1. 标准数据框架2. 标准数据框架下的生态2.1 数据解析2.2 数据处理2.3 数据可视化3. 标准数据框架下的可视化3.1 基础语法3.2 进阶语法1. 标准数据框架 制定一套标准的数据框架&#xff0c;可实现不…

python图像处理(中值滤波)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 中值滤波和均值滤波的区别,有点像中位数收入和平均收入的区别。比如有三个人,年收入分别是10万、1万和1千,那么他们的平均收入就是(10+1+0.1)/3,平均数是3.3万左右,但是中位数…

《真象还原》读书笔记——第二章 编写 MBR 主引导记录

2.1 计算机的启动过程 开机后运行的第一个程序是 BIOS 。 BIOS 搬运 MBR 并 跳转运行 MBR… 2.2 软件接力第一棒 BIOS 全名 基本输入输出系统。 2.2.1 实模式下的 1MB 内存分布 2.2.2 BIOS 是如何苏醒的 BIOS本身不需要修改&#xff0c;于是被写入了ROM中&#xff0c;被映…

更换新电脑,如何将旧电脑数据/文件传输到新电脑?

最好的数据迁移工具提供了一种简单的解决方案&#xff0c;可将您的数据从一台 PC 传输到另一台 PC。 如果您以前没有做过&#xff0c;那么数据迁移的整个过程可能看起来很吓人。无论您是企业用户还是家庭用户&#xff0c;尝试将所有文​​件和文件夹从一台计算机迁移到另一台计…

CCPC2022(桂林)

题目链接&#xff1a;https://codeforces.com/gym/104008 G Group Homework 题目大意&#xff1a;在树上选出两条链&#xff0c;使得在两条链选中的点中&#xff0c;只被一条链选中的点的点权和最大。 题解&#xff1a;显然两条链要么不相交&#xff0c;要么只相交于一个点。…

WhiteHole Base beta版本正式发布!

体验 当前版本为基础测试版本&#xff0c;测试效果可以前往演示视频查看&#xff1a;https://www.bilibili.com/video/BV18Y411D7sA/?spm_id_from333.999.0.0&vd_source641e71dfd1a118fb834c4a5d156688d5 在线体验地址为&#xff1a; http://47.100.239.95 数据将保存~ …

BGP基础实验

1.先配置好IP和环回 [R1]interface GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [R1-GigabitEthernet0/0/0]int l 0 [R1-LoopBack0]ip add 1.1.1.1 24 其他同理 2.在R2&#xff0c;R3&#xff0c;R4上配置OSPF ospf 1 area 0.0.0.0 network 3.3.3.3…

线段树(原理,模板)

文章目录线段树线段树代码(单点修改、区间查询)懒惰标记与区间修改树状数组与区间修改线段树 线段树是用来维护 区间信息 的数据结构 它可以在 O(log⁡n)O(\log n)O(logn) 的时间复杂度内实现单点修改、区间修改、区间查询&#xff08;区间求和&#xff0c;求区间最大值&…

Reasoning Through Memorization: Nearest Neighbor Knowledge Graph Embeddings论文阅读

研究问题 将基于记忆的方法与预训练语言模型相结合&#xff0c;以完成知识图谱补全任务 背景动机 传统模型无法处理未见实体记忆增强神经网络的相关进展&#xff0c;即在传统的计算模块之外添加单独的记忆存储模块 模型方法 首先使用预训练语言模型构建实体的知识库&#…

计算机网络第一章 计算机网络与因特网

1.0 目录[TOC]1.1 什么是Internet&#xff1f;1.1.1 最细微&#xff1a;图&#xff08;Graph&#xff09;Internet由结点Node和边Edge组成结点Node分为主机结点和交换结点边Edge分为接入网链路Access和主干链路Backbone结构图如下&#xff1a;1.1.2 网络的网络&#xff08;Netw…

【Python】数值计算基础

note scipy和numpy库可以便捷地进行科学计算&#xff0c;如线性代数、常微分方程数值求解、信号处理、图像处理、稀疏矩阵等。 文章目录note一、多项式基础1. 1 多项式表示和拟合1.2 多项式插值二、微积分计算2.1 数值积分2.2 符号积分三、矩阵运算3.1 线性方程组的求解3.2 矩…

PHP代码审计之MVC与ThinkPHP简介

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是PHP代码审计之MVC与ThinkPHP简介。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严…