详解Python中的进程和线程


Posted in Python onJune 23, 2021

进程是什么?

进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。

线程是什么?

线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。

进程和线程的区别

进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。或者说进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程则是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

进程和线程的关系:

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)CPU分给线程,即真正在CPU上运行的是线程。

详解Python中的进程和线程

并行和并发

并行处理(Parallel Processing)是计算机系统中能同时执行两个或者更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面,并行处理的主要目的是节省大型和复杂问题的解决时间。

并发处理(concurrency Processing)是指一个时间段中有几个程序都处于已经启动运行到运行完毕之间,而且这几个程序都是在同一处理机(CPU)上运行,但任意时刻点上只有一个程序在处理机(CPU)上运行

详解Python中的进程和线程

同步和异步

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
举个例子,打电话时就是同步通信,发短息时就是异步通信。

单例执行

from random import randint
from time import time, sleep


def download_task(filename):
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
    start = time()
    download_task('Python入门.pdf')
    download_task('av.avi')
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
    main()

运行是顺序执行,所以耗时是多个进程的时间总和

详解Python中的进程和线程

因为是单进程任务,所有任务都是排队进行所以这样执行效率非常的低。我们来添加多进程模式进行多进程同时执行,这样一个进程执行时,另一个进程无需等待,执行时间将大大缩短。

多进程

from random import randint
from time import time, sleep
from multiprocessing import Process
from os import getpid


def download_task(filename):
    print('启动下载进程,进程号:[%d]'%getpid())
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
    start = time()
    p1 = Process(target=download_task,args=('python入门.pdf',))
    p2 = Process(target=download_task,args=('av.avi',))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    # download_task('Python入门.pdf')
    # download_task('av.avi')
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
    main()

多个进程并排执行,总耗时就是最长耗时的那个进程的时间。

详解Python中的进程和线程

大致的执行流程如下图

详解Python中的进程和线程

多进程的特点是相互独立,不会共享全局变量,即在一个进程中对全局变量修改过后,不会影响另一个进程中的全局变量。

进程间通信

from random import randint
from time import time,sleep
from multiprocessing import Process
from os import getpid

time_to_download = 3
def download_task(filename):
    global time_to_download
    time_to_download += 1
    print('启动下载进程,进程号:[%d]'%getpid())
    print('开始下载%s...' % filename)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def download_task2(filename):
    global time_to_download
    print('启动下载进程,进程号:[%d]'%getpid())
    print('开始下载%s...' % filename)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def main():
    start = time()
    p1 = Process(target=download_task,args=('python入门.pdf',))
    p2 = Process(target=download_task2,args=('av.avi',))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
    main()

从执行结果可以看出,两个进程间的全局变量无法共享,所以它们是相互独立的

详解Python中的进程和线程

当然多进程也是可以进行通过一些方法进行数据共享的。可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序。

这里介绍Queue的常用进程通信的两种方法:
put 方法用以插入数据到队列中, put 方法还有两个可选参数: blocked 和 timeout。如果 blocked 为 True(默认值),并且 timeout 为正值,该方法会阻塞 timeout 指定的时间,直到该队列有剩余的空间。如果超时,会抛出 Queue.full 异常。如果 blocked 为 False,但该 Queue 已满,会立即抛出 Queue.full 异常。

get 方法可以从队列读取并且删除一个元素。同样, get 方法有两个可选参数: blocked和 timeout。如果 blocked 为 True(默认值),并且 timeout 为正值,那么在等待时间内没有取到任何元素,会抛出 Queue.Empty 异常。如果 blocked 为 False,有两种情况存在,如果Queue 有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty 异常。

Queue 队列实现进程间通信

from random import randint
from time import time,sleep
from multiprocessing import Process
import multiprocessing
from os import getpid

time_to_download = 3
def write(q):
    for i in ['python入门','av.avi','java入门']:
        q.put(i)
        print('启动写入进程,进程号:[%d]'%getpid())
        print('开始写入%s...' % i)  
        sleep(time_to_download)

def read(q):
    while True:
        if not q.empty():
            print('启动读取进程,进程号:[%d]'%getpid())
            print('开始读取%s...' % q.get())
            sleep(time_to_download)
        else:
            break

def main():
    q = multiprocessing.Queue()
    p1 = Process(target=write,args=(q,))
    p2 = Process(target=read,args=(q,))
    p1.start()
    p1.join()
    p2.start()
    p2.join()


if __name__ == '__main__':
    main()

上一个进程写入的数据通过Queue队列共享给了下一个进程,然后下一个进程可以直接进行使用,这样就完成了多进程间的数据共享。

详解Python中的进程和线程

进程池

Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
进程池中常见三个方法:

◆apply:串行
◆apply_async:并行
◆map

多线程

from random import randint
from time import time, sleep
from threading import Thread
from os import getpid

def download_task(filename):
    print('启动下载进程,进程号:[%d]' % getpid())
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def main():
    start = time()
    p1 = Thread(target=download_task, args=('python入门.pdf',))
    p2 = Thread(target=download_task, args=('av.avi',))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('总共耗费了%.2f秒.' % (end - start))

if __name__ == '__main__':
    main()

多线程执行因为GIL锁的存在,实际上执行是进行单线程,即一次只执行一个线程,然后在切换其他的线程进行执行,因为其中切换的时间非常的短,所以看上去依然像是多线程一起执行。

详解Python中的进程和线程

通过继承Thread类的方式来创建自定义的线程类,然后再创建线程对象并启动线程

from random import randint
from threading import Thread
from time import time, sleep

class DownloadTask(Thread):
    def __init__(self, filename):
        super().__init__()
        self._filename = filename

    def run(self):
        print('开始下载%s...'% self._filename)
        time_to_download = randint(5,10)
        sleep(time_to_download)
        print('%s下载完成!耗费了%d秒' %(self._filename, time_to_download))

def main():
    start = time()
    t1 = DownloadTask('python入门')
    t2 = DownloadTask('av.avi')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print('共耗费了%.2f秒'%(end - start))

if __name__ == '__main__':
    main()

多线程使用类还是函数执行的结果完全一致,具体怎么使用可以结合自己的使用场景。

详解Python中的进程和线程

到此这篇关于详解Python中的进程和线程的文章就介绍到这了,更多相关Python进程和线程内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
使用Python的urllib和urllib2模块制作爬虫的实例教程
Jan 20 Python
12步入门Python中的decorator装饰器使用方法
Jun 20 Python
Python判断列表是否已排序的各种方法及其性能分析
Jun 20 Python
python开发环境PyScripter中文乱码问题解决方案
Sep 11 Python
使用python读取txt文件的内容,并删除重复的行数方法
Apr 18 Python
Python实现合并两个有序链表的方法示例
Jan 31 Python
详解python使用turtle库来画一朵花
Mar 21 Python
Python实现二叉搜索树BST的方法示例
Jul 30 Python
python实现贪吃蛇双人大战
Apr 18 Python
python 利用Pyinstaller打包Web项目
Oct 23 Python
OpenCV+Python3.5 简易手势识别的实现
Dec 21 Python
python实现图片转字符画
Feb 19 Python
详解Go语言运用广度优先搜索走迷宫
常用的Python代码调试工具总结
Django+Celery实现定时任务的示例
Python django中如何使用restful框架
Python基础之变量的相关知识总结
Jun 23 #Python
浅谈Python数学建模之固定费用问题
浅谈Python数学建模之整数规划
You might like
全局记录程序片段的运行时间 正确找到程序逻辑耗时多的断点
2011/01/06 PHP
Smarty简单生成表单元素的方法示例
2016/05/23 PHP
php封装的page分页类完整实例
2016/10/18 PHP
php实现微信支付之退款功能
2018/05/30 PHP
JS 巧妙获取剪贴板数据 Excel数据的粘贴
2009/07/09 Javascript
模仿JQuery.extend函数扩展自己对象的js代码
2009/12/09 Javascript
javascript中的float运算精度实例分析
2010/08/21 Javascript
JQUERY 实现窗口滚动搜索框停靠效果(类似滚动停靠)
2013/03/27 Javascript
js 获取元素下面所有li的两种方法
2014/04/14 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
详解vue-cli 脚手架项目-package.json
2017/07/04 Javascript
使用Node.js实现简易MVC框架的方法
2017/08/07 Javascript
浅谈从React渲染流程分析Diff算法
2018/09/08 Javascript
vue实现双向绑定和依赖收集遇到的坑
2018/11/29 Javascript
详解Vue源码学习之双向绑定
2019/04/10 Javascript
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
Linux下用Python脚本监控目录变化代码分享
2015/05/21 Python
Django中对通过测试的用户进行限制访问的方法
2015/07/23 Python
python append、extend与insert的区别
2016/10/13 Python
Python多进程库multiprocessing中进程池Pool类的使用详解
2017/11/24 Python
python3 cvs将数据读取为字典的方法
2018/12/22 Python
TensorFlow获取加载模型中的全部张量名称代码
2020/02/11 Python
Python实现一个优先级队列的方法
2020/07/31 Python
Python 内存管理机制全面分析
2021/01/16 Python
基于css3实现漂亮便签样式
2013/03/18 HTML / CSS
G-Form护具官方网站:美国运动保护装备
2019/09/04 全球购物
在Ajax应用中信息是如何在浏览器和服务器之间传递的
2016/05/31 面试题
工作室成员个人发展规划范文
2014/01/24 职场文书
本科生导师推荐信范文
2014/05/18 职场文书
小学生迎国庆演讲稿
2014/09/05 职场文书
中学生的1000字检讨书
2014/10/11 职场文书
大学生党员个人总结
2015/02/13 职场文书
2015感人爱情寄语
2015/02/26 职场文书
检举信的写法
2019/04/10 职场文书
看看如何用Python绘制小米新版天价logo
2021/04/20 Python
Oracle使用别名的好处
2022/04/19 Oracle