Python进程与线程开发

news2025/5/23 1:35:17

目录

multiprocessing模块

线程的开发

threading模块 

 setDaemon

死锁 

 线程间的通信


multiprocessing模块

运行python的时候,我们都是在创建并运行一个进程,(linux中一个进程可以fork一个子进程,并让这个子进程exec另外一个程序)。在python中,我们通过标准库中的subprocess包来fork一个子进程,并且运行一个外部的程序。subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所欲我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

multiprocessing 包同时提供本地和远程并发,使用子进程代替线程,有效避免 Global Interpreter Lock 带来的影响。

from multiprocessing import Process
import os
from time import sleep, time
def test1(name):
  
  print("当前进程的ID", os.getpid())
  print("父进程的ID", os.getppid())
  print("当前进程的名字:", name)
  
  sleep(3)

if __name__ == '__main__':
  start = time()
  # 创建多个子进程,并且把这些子进程放入列表中
  process_list = []
  print("主进程的ID", os.getpid())
  for i in range(10):
    
    p = Process(target=test1, args=('process-%s' % i,))
    
    p.start()
    process_list.append(p)

类包装:自定义一个Process进程类,该类中的run函数由一个子进程调用执行

from multiprocessing import Process
import os
from time import sleep, time
# 自定义一个进程类 继承Process类
class MyProcess(Process):
  def __init__(self, name):
    Process.__init__(self)
    self.name = name
  def run(self):
    
    print("当前进程的ID", os.getpid())
    print("父进程的ID", os.getppid())
    print("当前进程的名字:", self.name)
    sleep(3)

if __name__ == '__main__':
  print("主进程ID", os.getpid())
  
  start = time()
  process_list = []
  for i in range(10):
    
    p = MyProcess("process-%s" % i)
    
    p.start()
    process_list.append(p)
  for p in process_list:
    
    p.join()
    
    end = time() - start
    print(end)

线程的开发

Python 的标准库提供了两个模块:thread 和 threading,thread 是低级模块,threading 是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading 这个高级模块。

多线程概念

多线程使得系统可以在单独的进程中执行并发任务。虽然进程也可以在独立的内存空间中并发执行,但是其系统开销会比较大。生成一个新进程必须为其分配独立的地址空间,并维护其代码段、堆栈段和数据段等,这种开销是巨大的。另外,进程间的通信实现也不方便。在程序功能日益复杂的时候,需要有更好的系统模型来满足要求,线程由此产生了。 线程是“轻量级”的,一个进程中的线程使用同样的地址空间,且共享许多资源。启动线程的时间远远小于启动进程的时间和空间,而且,线程间的切换也要比进程间的切换快得多。由于使用同样的地址空间,所以线程之间的数据通信比较方便,一个进程下的线程之间可以直接使用彼此的数据。当然,这种方便性也会带来一些问
题,特别是同步问题。 多线程对于那些I/O受限的程序特别适用。其实使用多线程的一个重要目的,就是最大化地利用CPU的资源。当某一线程在等待I/O的时候,另外一个线程可以占用CPU资源。如最简单的GUI程序,一般需要有一个任务支持前台界面的交互,还要有一个任务支持后台的处理。 

多线程运行的作用:

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

线程可以分为内核线程和用户线程,内核线程由操作系统内核创建和撤销;用户线程不需要内核支持而在用户程序中实现的线程。

创建线程 

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。

threading模块 

import time
def say():
  print("这是单线程!")
  time.sleep(1)
if __name__ == "__main__":
  start = time.time()
  for i in range(5):
    say()
  end = time.time()
  print(f'使用时间:{end - start}')
import threading
import time
def say():
  print("这是多线程")
  time.sleep(1)
if __name__ == "__main__":
  '''入口'''
  start = time.time()
  for i in range(5):
    # 通过threading下的Thread方法创建线程
    t = threading.Thread(target=say)
    t.start()  # 启动线程
  end = time.time()
  print(f'使用时间:{end - start}')

 可以明显看出使用了多线程并发的操作,花费时间要短很多。

程序是通过threading模块下的Thread的类,去实例化一个此对象,并调用方法,实现生成多线程,target参数表示线程需要执行的方法,通过对象的start的方法,开启线程。

import threading
from time import sleep,ctime
def sing():
  for i in range(3):
    print("唱歌...%d"%i)
    sleep(1)
def dance():
  for i in range(3):
    print("跳舞...%d"%i)
    sleep(1)
if __name__ == '__main__':
  print('---开始---:%s'%ctime())
  t1 = threading.Thread(target=sing)
  t2 = threading.Thread(target=dance)
  t1.start()
  t2.start()
  sleep(5) 
  print('---结束---:%s'%ctime())

 join方法

该方法将等待,一直到它调用的线程终止,它的名字表示调用的线程会一直等待,直到指定的线程加入它。join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止。

from threading import Thread
from time import sleep, time
def run(name):
  
  print("Threading:{} start".format(name))
  sleep(3)
  print("Threading:{} end".format(name))
if __name__ == '__main__':
  
  # 开始时间
  start = time()
  # 创建线程列表
  t_list = []
  # 循环创建线程
  for i in range(10):
    t = Thread(target=run, args=('t{}'.format(i),))
    t.start()
    t_list.append(t)
  # 等待线程结束
  for t in t_list:
    t.join()
  # 计算使用时间
  end = time() - start
  print(end)

 setDaemon

将线程声明为守护线程,在start() 方法调用之前设置,这个方法和join是相反的。

有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,
这时就可以用setDaemon方法。

from threading import Thread
import time
def foo():
  print(123)
  time.sleep(1)
  print("end123")
def bar():
  print(456)
  time.sleep(3)
  print("end456")
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon = True
t1.start()
t2.start()
print("~~~")

同步锁与GIL的关系 

GIL本质是一把互斥锁,但GIL锁住的是解释器级别的数据,同步锁,锁的是解释器以外的共享资源,例如:硬盘上的文件 控制台,对于这种不属于解释器的数据资源就应该自己加锁处理 。

GIL 的作用是:对于一个解释器,只能有一个thread在执行bytecode。所以每时每刻只有一条bytecode在被执行一个thread。GIL保证了bytecode 这层面上是thread safe的。

死锁 

在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。 

产生死锁的四个必要条件:

  • 互斥条件:一个资源每次只能被一个线程使用。
  • 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:线程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。 
from threading import Thread,Lock
from time import sleep
class Task1(Thread):
  def run(self):
    while True:
      if lock1.acquire():
        print("------Task 1 -----")
        sleep(0.5)
        lock2.release()
class Task2(Thread):
  def run(self):
    while True:
      if lock2.acquire():
        print("------Task 2 -----")
        sleep(0.5)
        lock3.release()

class Task3(Thread):
  def run(self):
    while True:
      if lock3.acquire():
        print("------Task 3 -----")
        sleep(0.5)
        lock1.release()

lock1 = Lock()
#创建另外一把锁
lock2 = Lock()
lock2.acquire()

lock3 = Lock()
lock3.acquire()
t1 = Task1()
t2 = Task2()
t3 = Task3()
t1.start()
t2.start()
t3.start()

 线程间的通信

在加锁的情况下,程序就变成了串行,也就是单线程,而有时,我们在不用考虑数据安全时,不用加锁,程序就变成了并行,也就是多线程。为了避免业务开启过多的线程时。我们就可以通过信号量(Semaphore)来设置指定个数的线程。 

from threading import Thread, BoundedSemaphore
from time import sleep
def an_jian(num):
  semapshore.acquire()
  print('第{}个人安检完成!'.format(num))
  sleep(2)
  semapshore.release()

if __name__ == '__main__':
  semapshore = BoundedSemaphore(3)
  for i in range(20):
    thread = Thread(target=an_jian, args=(i,))
    thread.start()

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

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

相关文章

MySQL如何用phpMyAdmin创建定时任务事件来执行SQL语句删除_edit_lock和_edit_last?

前面跟大家分享了『WordPress如何批量删除wp_postmeta数据表无用的_edit_lock和_edit_last数据?』和『宝塔面板在计划任务中怎么执行SQL语句删除_edit_lock和_edit_last?』,但是有些站长并不是使用宝塔面板,那么我们如何时间定时删…

阅读基础知识1

一 网络 1. 三次握手四次挥手 三次握手:为了建立长链接进行交互即建立一个会话,使用 http/https 协议 ① 客户端产生初始化序列号 Seqx ,向服务端发送建立连接的请求报文,将 SYN1 同步序列号; ② 服务端接收建立连接…

走近 AI Infra 架构师:在高速飞驰的大模型“赛车”上“换轮子”的人

如果把大模型训练比作 F1 比赛,长凡所在的团队就是造车的人,也是在比赛现场给赛车换轮子的人。1% 的训练提速,或者几秒之差的故障恢复时间,累积起来,都能影响到几百万的成本。长凡说:“大模型起来的时候&am…

日本科技巨头富士通遭遇网络攻击,客户数据被窃

日本科技巨头富士通3月15日发布通告,宣称公司经历了一起网络攻击事件,客户个人数据已被黑客窃取。 富士通在一份通知中写道:“我们已经确认有几台商用计算机上存在恶意软件,并且经过我们的内部调查,发现包含个人信息和…

Linux权限维持后门及应急响应

本次应急响应实验用kali和centos7来充当攻击机和靶机 kali:192.168.10.130 centos7:192.168.10.155 前提: 用kali连接到centos7上面ssh root192.168.10.155 一、SSH软链接 任意密码登录即可发现程度:|||||| ln -sf /usr/sbi…

卓越巨人wzy

解法&#xff1a; 向下取整同理&#xff0c;f(n)20230416-n 当n20230416时&#xff0c;f&#xff08;n&#xff09;0&#xff0c;之后由于向上取整&#xff0c;结果恒为0. #include<iostream> #include<algorithm> #include<vector> using namespace std; …

网站如何搭建 网站搭建的详细步骤

网站如何搭建 网站搭建的详细步骤 一.领取一个免费域名和SSL证书&#xff0c;和CDN 1.打开网站链接&#xff1a;https://www.rainyun.com/z22_ 2.在网站主页上&#xff0c;您会看到一个"登陆/注册"的选项。 3.点击"登陆/注册"&#xff0c;然后选择"…

下拉树级带搜索功能

可以直接复制粘贴到自己的项目里,方法处把接口替换一下 <template><div><el-popoverplacement"bottom"width"200"trigger"click"><el-inputslot"reference"class"mrInput":placeholder"placehol…

巨细!Python爬虫详解

爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在 FOAF 社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff1b;它是一种按照一定的规则&#xff0c;自动地抓取网络信息的程序或者脚本。 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那…

二、yocto 集成ros2(基于raspberrypi 4B)

yocto 集成ros2 yocto 集成ros21. 下载ros layer2. 编译集成ros3. 功能验证 yocto 集成ros2 本篇文章为基于raspberrypi 4B单板的yocto实战系列的第二篇文章。 一、yocto 编译raspberrypi 4B并启动 本节我们将ros2机器人操作系统移植到我们的yocto系统里面。 1. 下载ros laye…

Ansible基本介绍与模块使用

目录 引言 一、Ansible简介 &#xff08;一&#xff09;基本概述 &#xff08;二&#xff09;主要特点 二、Ansible安装及基本组件 &#xff08;一&#xff09;yum安装 &#xff08;二&#xff09;编译安装 &#xff08;三&#xff09;基本配置信息 1.主配置文件 2.主…

v-bind 绑定 class 与 style 基础用法

使用 v-bind 指令绑定 class 和 style 时语法相对复杂一些&#xff0c;这两者是可以互相替代的&#xff0c;均用于响应更新HTML元素的属性&#xff0c; v-bind 绑定 class 属性可以改写成绑定 style 属性&#xff0c;只是 css 属性位置变了而已。 1. 绑定 class 属性 1.1 数组…

GPT-4与Claude3、Gemini、Sora:AI领域的技术创新与突破

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚…

考研失败, 学点Java打小工_Day3_卫语句_循环

1 编码规范——卫语句 表达异常分支时&#xff0c;少用if-else方式。   比如成绩判断中对于非法输入的处理&#xff1a; /*>90 <100 优秀>80 <90 良好>70 <80 一般>60 <70 及格<60 不及格*/Testpu…

行业领袖齐聚香港,共襄区块链盛宴——Symbiosis 联合创始人Nick Avramov确认出席Hack.Summit() 2024区块链开发者大会

随着区块链技术的飞速进步和广泛应用&#xff0c;一场区块链行业的重量级盛会即将在香港数码港隆重举行。由Hack VC主办、AltLayer和Berachain协办&#xff0c;并得到Solana、The Graph、Blockchain Academy、ScalingX、0G、SNZ和数码港等机构的合作支持&#xff0c;由Techub N…

【全开源】JAVA姓氏头像情侣头像家庭头像赚钱签名头像谐音顽埂头像设计小程序头像大全系统源码支持微信小程序+微信公众号+H5|博纳软云

一、功能介绍 用户端&#xff1a;查看近期生成的头像&#xff0c;我的团队&#xff0c;分享好友&#xff0c; 姓氏头像&#xff0c;情侣头像&#xff0c;亲子头像&#xff0c;家庭头像 选择模板&#xff0c;个人资料&#xff0c;修改资料&#xff0c;注销账号。 我们技术使用…

你真的会做抖音小店吗?你做抖店的方法是正确的吗?教学分享

大家好&#xff0c;我是电商花花。 新的一年&#xff0c;不少做抖店的商家都会产生一个疑问&#xff0c;2024年抖音小店无货源还能继续做吗&#xff1f; 做无货源模式还会被处罚吗&#xff1f; 先说答案&#xff0c;2024年抖音小店无货源能做&#xff0c;不仅能做且仍然是抖音…

简明 FastAPI 并发请求指南

在当今的数字化世界中&#xff0c;网络用户对于高速响应和持续连接的诉求日益显著。这促使了基于 Python 构建的 FastAPI 框架受到广泛关注&#xff0c;它不仅现代化且效率极高&#xff0c;而且简化了并行请求的处理。本篇文章旨在探讨 FastAPI 如何处理这类请求&#xff0c;并…

Java项目:64 ssm营业厅宽带系统+jsp

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 角色&#xff1a;管理员、用户 管理员的功能有&#xff1a;查看已发布的用户信息&#xff0c;修改用户信息或更换用户内容&#xff0c;用户信息作废&…

计算机二级Python题目12

目录 1. 基础题 1.1 基础题1 1.2 基础题2 1.3 基础题3 2. turtle画图题 3. 大题 3.1 大题1 3.2 大题2 1. 基础题 1.1 基础题1 sinput("请输入一个小数&#xff1a;") ss[::-1] cs0 for c in s:if c.:breakcseval(c) print({:*>10}.format(cs)) 1.2 基础…