实例详解Python的进程,线程和协程


Posted in Python onMarch 13, 2022

前言

本文用Python实例阐述了一些关于进程、线程和协程的概念,由于水平有限,难免出现错漏,敬请批评改正。

前提条件

熟悉Python基本语法熟悉Python操作进程、线程、协程的相关库

相关介绍

Python是一种跨平台的计算机程序设计语言。是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。

实例详解Python的进程,线程和协程

例如,

实例详解Python的进程,线程和协程

实验环境

  • Python 3.x (面向对象的高级语言)
  • Multiprocessing(Python库)
  • Threading(Python库)
  • Asyncio(Python库)
  • Time(Python库)
  • Random(Python库)

进程

进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid(进程号)。 一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。

实例详解Python的进程,线程和协程

 创建进程步骤:

1.首先要导入 multiprocessing 中的 Process;

2.创建一个 Process 对象;

3.创建 Process 对象时,可以传递参数;

4.使用 start()启动进程;

5.结束进程。

import os 
from multiprocessing import Process
import time
def pro_func(name,age,**kwargs):
	print("进程正在运行,name=%s, age=%d, pid=%d" %(name, age, os.getpid()))
	print('kwargs参数值',kwargs)
	time.sleep(0.1)
if __name__=="__main__":
    p=Process(target=pro_func,args=('Friendship',18),kwargs={'爱好':'Python'})
    print('启动进程')
    p.start()
    print('程是否还在活着:',p.is_alive())# 判断进程进程是否还在活着
    time.sleep(0.5)
    # 1 秒钟之后,立刻结束进程
    print('结束进程')
    p.terminate() # 不管任务是否完成,立即终止进程
    p.join() # 等待子进程执行结束
    print('程是否还在活着:',p.is_alive())# 判断进程进程是否还在活着

实例详解Python的进程,线程和协程

注意:进程间不共享全局变量。

多进程

以一个读写程序为例,main函数为一个主进程,write函数为一个子进程,read函数为另一个子进程,然后两个子进程进行读写操作。

import os
import time
import random
from multiprocessing import Process,Queue
# 写数据函数
def write(q):
    for value in ['I','love','Python']:
        print('在队列里写入 %s ' % value)
        q.put(value)
        time.sleep(random.random())
# 读数据函数
def read(q):
    while True:
        if not q.empty():
            value  = q.get(True)
            print('从队列中读取 %s ' % value)
            time.sleep(random.random())
        else:
            break
if __name__=="__main__": # 主进程
    # 主进程创建 Queue,并传给各个子进程
    q=Queue()
    # 创建两个进程
    pw=Process(target=write,args=(q,))
    pr=Process(target=read,args=(q,))
    # 启动子进程 pw
    pw.start()
    # 等待 pw结束
    pw.join()
    # 启动子进程 pr
    pr.start()
    # 等待 pw结束
    pr.join()
    print('End!')

实例详解Python的进程,线程和协程

用进程池对多进程进行操作

from multiprocessing import Manager,Pool
import os,time,random
def read(q):
    print("read进程 启动(%s),主进程为(%s)" % (os.getpid(), os.getppid()))
    for i in range(q.qsize()):
        print("read进程 从 Queue 获取到消息:%s" % q.get(True))
def write(q):
    print("write进程 启动(%s),主进程为(%s)" % (os.getpid(), os.getppid()))
    for i in "Python":
        q.put(i)
if __name__=="__main__":
    print("主进程(%s) start" % os.getpid())
    q = Manager().Queue() # 使用 Manager 中的 Queue
    # 定义一个进程池
    po = Pool()
    # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
    po.apply_async(write, (q,))
    time.sleep(1) # 先让上面的任务向 Queue 存入数据,然后再让下面的任务开始从中取数据
    po.apply_async(read, (q,))
    po.close() # 关闭进程池,关闭后 po 不再接收新的请求
    po.join() # 等待 po 中所有子进程执行完成,必须放在 close 语句之后
    print("(%s) End!" % os.getpid())

实例详解Python的进程,线程和协程

线程

线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。

实例详解Python的进程,线程和协程

实例详解Python的进程,线程和协程

上图,红框表示进程号(PID)为1624的进程,有118个线程。

使用_thread模块实现

import _thread
import time
import random
# 为线程定义一个函数
def print_time(threadName):
    count = 0
    while count < 5:
        time.sleep(random.random())
        count += 1
        print ("%s: %s" % (threadName, time.ctime(time.time())))
# 创建两个线程
try:
    _thread.start_new_thread(print_time, ("Thread-1",))
    _thread.start_new_thread(print_time, ("Thread-2",))
except:
    print ("Error: 无法启动线程")
while True:
	pass

实例详解Python的进程,线程和协程

使用 threading 模块实现

# 使用 threading 模块创建线程 
import threading
import time
import random
class myThread(threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = random.random()
    def run(self):
        print ("开始线程:" + self.name)
        print_time(self.name, 5)
        print ("退出线程:" + self.name)
def print_time(threadName, count):
    while count:
        time.sleep(random.random())
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        count -= 1
# 创建两个线程
thread1 = myThread(1, "Thread-1")
thread2 = myThread(2, "Thread-2")
# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主线程")

实例详解Python的进程,线程和协程

协程

  • 协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
  • 当出现IO阻塞的时候,由协程的调度器进行调度,通过将数据流立刻yield掉(主动让出),并且记录当前栈上的数据,阻塞完后立刻再通过线程恢复栈,并把阻塞的结果放到这个线程上去跑,这样看上去好像跟写同步代码没有任何差别,这整个流程可以称为coroutine。
  • 由于协程的暂停完全由程序控制,发生在用户态上;而线程的阻塞状态是由操作系统内核来进行切换,发生在内核态上。因此,协程的开销远远小于线程的开销。

使用asyncio模块实现

import asyncio
import time
import random
async def work(msg):
    print("收到的信息:'{}'".format(msg))
    print("{}1{}".format("*"*10,"*"*10)) # 为了方便,展示结果
    await asyncio.sleep(random.random())
    print("{}2{}".format("*"*10,"*"*10)) # 为了方便,展示结果
    print(msg)
async def main():
	# 创建两个任务对象(协程),并加入到事件循环中
    Coroutines1 = asyncio.create_task(work("hello"))
    Coroutines2 = asyncio.create_task(work("Python"))
    print("开始时间: {}".format(time.asctime(time.localtime(time.time()))))
    await Coroutines1  # 此时并发运行Coroutines1和Coroutines2
    print("{}3{}".format("*"*10,"*"*10)) # 为了方便,展示结果
    await Coroutines2 # await相当于挂起当前任务,去执行其他任务,此时是堵塞的
    print("{}4{}".format("*"*10,"*"*10)) # 为了方便,展示结果
    print("结束时间:{}".format(time.asctime(time.localtime(time.time()))))
asyncio.run(main())# asyncio.run(main())创建一个事件循环,并以main为主要程序入口

实例详解Python的进程,线程和协程

总结

  • 进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
  • 线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
  • 协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!  

Python 相关文章推荐
python使用rabbitmq实现网络爬虫示例
Feb 20 Python
python getopt详解及简单实例
Dec 30 Python
python 接口测试response返回数据对比的方法
Feb 11 Python
Python实现的计算马氏距离算法示例
Apr 03 Python
Python GUI Tkinter简单实现个性签名设计
Jun 19 Python
python 列表中[ ]中冒号‘:’的作用
Apr 30 Python
使用pycharm在本地开发并实时同步到服务器
Aug 02 Python
pandas和spark dataframe互相转换实例详解
Feb 18 Python
python实现一次性封装多条sql语句(begin end)
Jun 06 Python
python使用Windows的wmic命令监控文件运行状况,如有异常发送邮件报警
Jan 30 Python
Python如何利用正则表达式爬取网页信息及图片
Apr 17 Python
Python利用Turtle绘制哆啦A梦和小猪佩奇
Apr 04 Python
Python获取指定日期是"星期几"的6种方法
Python+tkinter实现高清图片保存
Python中的 Set 与 dict
Mar 13 #Python
Python echarts实现数据可视化实例详解
分享3个非常实用的 Python 模块
Mar 03 #Python
详解在OpenCV中如何使用图像像素
 Python 中 logging 模块使用详情
Mar 03 #Python
You might like
全国FM电台频率大全 - 16 河南省
2020/03/11 无线电
PHP Ajax中文乱码问题解决方法
2009/02/27 PHP
php获取mysql数据库中的所有表名的代码
2011/04/23 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
Laravel 5.5 的自定义验证对象/类示例代码详解
2017/08/29 PHP
PHP延迟静态绑定使用方法实例解析
2020/09/05 PHP
jQuery结合PHP+MySQL实现二级联动下拉列表[实例]
2011/11/15 Javascript
非常漂亮的相册集 使用jquery制作相册集
2016/04/28 Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
2016/05/04 Javascript
WEB开发之注册页面验证码倒计时代码的实现
2016/12/15 Javascript
微信小程序城市定位的实现实例(获取当前所在国家城市信息)
2017/05/17 Javascript
node.js中fs.stat与fs.fstat的区别详解
2017/06/01 Javascript
Vuex利用state保存新闻数据实例
2017/06/28 Javascript
详解js的作用域、预解析机制
2018/02/05 Javascript
vue2.0在没有dev-server.js下的本地数据配置方法
2018/02/23 Javascript
puppeteer实现html截图的示例代码
2019/01/10 Javascript
用js简单提供增删改查接口
2019/05/12 Javascript
Node.js 获取微信JS-SDK CONFIG的方法示例
2019/05/21 Javascript
webpack4 SplitChunks实现代码分隔详解
2019/05/23 Javascript
一个手写的vue放大镜效果
2019/08/09 Javascript
python自动安装pip
2014/04/24 Python
浅谈Python 字符串格式化输出(format/printf)
2016/07/21 Python
详解Python之unittest单元测试代码
2018/01/24 Python
美国迪克体育用品商店:DICK’S Sporting Goods
2018/07/24 全球购物
June Jacobs尊积帕官网:知名的spa水疗护肤品牌
2019/03/21 全球购物
舞蹈教师自荐信
2014/01/27 职场文书
物业管理毕业生的自我评价
2014/02/17 职场文书
国培计划培训感言
2014/03/11 职场文书
班组长竞聘书
2014/03/31 职场文书
绿色环保口号
2014/06/12 职场文书
社区活动策划方案
2014/08/21 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
2014年禁毒工作总结
2014/11/24 职场文书
2014年乡镇民政工作总结
2014/12/02 职场文书
Redis超详细讲解高可用主从复制基础与哨兵模式方案
2022/04/07 Redis
Windows7下FTP搭建图文教程
2022/08/05 Servers