详解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代码真的很爽
Aug 26 Python
paramiko模块安装和使用(远程登录服务器)
Jan 27 Python
Django发送html邮件的方法
May 26 Python
python实现数独算法实例
Jun 09 Python
浅谈Python 对象内存占用
Jul 15 Python
Flask入门之上传文件到服务器的方法示例
Jul 18 Python
用python做游戏的细节详解
Jun 25 Python
tensorflow estimator 使用hook实现finetune方式
Jan 21 Python
Python中zip()函数的解释和可视化(实例详解)
Feb 16 Python
Selenium基于PIL实现拼接滚动截图
Apr 10 Python
浅谈matplotlib 绘制梯度下降求解过程
Jul 12 Python
python 实现德洛内三角剖分的操作
Apr 22 Python
详解Go语言运用广度优先搜索走迷宫
常用的Python代码调试工具总结
Django+Celery实现定时任务的示例
Python django中如何使用restful框架
Python基础之变量的相关知识总结
Jun 23 #Python
浅谈Python数学建模之固定费用问题
浅谈Python数学建模之整数规划
You might like
php创建多级目录代码
2008/06/05 PHP
PHP 变量的定义方法
2010/01/26 PHP
优化php效率,提高php性能的一些方法
2011/03/24 PHP
ThinkPHP3.1新特性之对页面压缩输出的支持
2014/06/19 PHP
深入解析PHP中foreach语句控制数组循环的用法
2015/11/30 PHP
PHP微信开发之查询城市天气
2016/06/23 PHP
PHP实现创建微信自定义菜单的方法示例
2017/07/14 PHP
php中pcntl_fork创建子进程的方法实例
2019/03/14 PHP
laravel config文件配置全局变量的例子
2019/10/13 PHP
PHP pthreads v3在centos7平台下的安装与配置操作方法
2020/02/21 PHP
javascript中字符串拼接需注意的问题
2010/07/13 Javascript
一样的table?不一样的table(可编辑状态table)
2012/09/19 Javascript
jquery和ajax的关系详细介绍
2013/11/29 Javascript
Bootstrap每天必学之按钮(一)
2015/11/24 Javascript
jQuery easyUI datagrid 增加求和统计行的实现代码
2016/06/01 Javascript
15款最好的Bootstrap在线编辑器
2016/08/03 Javascript
js实现PC端根据IP定位当前城市地理位置
2017/02/22 Javascript
深入浅析Vue中的slots/scoped slots
2018/04/03 Javascript
js实现左右两侧浮动广告
2018/07/09 Javascript
JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】
2019/02/22 Javascript
小程序封装路由文件和路由方法(5种全解析)
2019/05/26 Javascript
Python中实现常量(Const)功能
2015/01/28 Python
OPENCV去除小连通区域,去除孔洞的实例讲解
2018/06/21 Python
3个用于数据科学的顶级Python库
2018/09/29 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
用python做游戏的细节详解
2019/06/25 Python
文件上传服务器-jupyter 中python解压及压缩方式
2020/04/22 Python
Linux文件系统类型
2012/02/15 面试题
八年级语文教学反思
2014/02/11 职场文书
经管应届生求职信范文
2014/05/18 职场文书
入党介绍人考察意见
2015/06/01 职场文书
股东出资协议书
2016/03/21 职场文书
用Python简陋模拟n阶魔方
2021/04/17 Python
Java Spring Lifecycle的使用
2022/05/06 Java/Android
MySQL一劳永逸永久支持输入中文的方法实例
2022/08/05 MySQL