实例详解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的字典和列表的使用中一些需要注意的地方
Apr 24 Python
python调用xlsxwriter创建xlsx的方法
May 03 Python
python实现根据指定字符截取对应的行的内容方法
Oct 23 Python
Python爬虫之正则表达式的使用教程详解
Oct 25 Python
pymysql模块的使用(增删改查)详解
Sep 09 Python
Pytorch中index_select() 函数的实现理解
Nov 19 Python
torch 中各种图像格式转换的实现方法
Dec 26 Python
基于python3抓取pinpoint应用信息入库
Jan 08 Python
Python tornado上传文件的功能
Mar 26 Python
Python基于mediainfo批量重命名图片文件
Dec 29 Python
Python数据清洗工具之Numpy的基本操作
Apr 22 Python
python scrapy简单模拟登录的代码分析
Jul 21 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
php5编程中的异常处理详细方法介绍
2008/07/29 PHP
第二章 PHP入门基础之php代码写法
2011/12/30 PHP
解析php取整的几种方式
2013/06/25 PHP
php 强制下载文件实现代码
2013/10/28 PHP
PHP mysql事务问题实例分析
2016/01/18 PHP
支付宝支付开发――当面付条码支付和扫码支付实例
2016/11/04 PHP
PHP编程计算日期间隔天数的方法
2017/04/26 PHP
php实现页面纯静态的实例代码
2017/06/21 PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
2018/04/20 PHP
新手入门常用代码集锦
2007/01/11 Javascript
仅IE9/10同时支持script元素的onload和onreadystatechange事件分析
2011/04/27 Javascript
基于jquery跨浏览器显示的file上传控件
2011/10/24 Javascript
jQuery实现的Div窗口震动特效
2014/06/09 Javascript
一个不错的js html页面倒计时可精确到秒
2014/10/22 Javascript
javascript制作的cookie封装及使用指南
2015/01/02 Javascript
JS实现合并两个数组并去除重复项只留一个的方法
2015/12/17 Javascript
原生js封装自定义滚动条
2017/03/24 Javascript
判断滚动条滑到底部触发事件(实例讲解)
2017/11/15 Javascript
vue路由拦截及页面跳转的设置方法
2018/05/24 Javascript
ES6函数和数组用法实例分析
2020/05/23 Javascript
使用Python写CUDA程序的方法
2017/03/27 Python
Python实现的微信公众号群发图片与文本消息功能实例详解
2017/06/30 Python
python中数据爬虫requests库使用方法详解
2018/02/11 Python
[原创]Python入门教程5. 字典基本操作【定义、运算、常用函数】
2018/11/01 Python
python对象销毁实例(垃圾回收)
2020/01/16 Python
pytorch下的unsqueeze和squeeze的用法说明
2021/02/06 Python
详解CSS 3 中的 calc() 方法
2018/01/12 HTML / CSS
canvas画布实现手写签名效果的示例代码
2019/04/23 HTML / CSS
台湾母婴用品限时团购:妈咪爱
2018/08/03 全球购物
《最可爱的人》教学反思
2014/02/14 职场文书
《小山羊和小灰兔》教学反思
2014/02/19 职场文书
爱心捐款倡议书
2014/04/14 职场文书
羊脂球读书笔记
2015/06/30 职场文书
学生会任命书范本
2015/09/21 职场文书
python编写五子棋游戏
2021/05/25 Python
CSS实现章节添加自增序号的方法
2021/06/23 HTML / CSS