详解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基于PycURL自动处理cookie的方法
Jul 25 Python
Python中subprocess的简单使用示例
Jul 28 Python
Python内置函数OCT详解
Nov 09 Python
python 函数传参之传值还是传引用的分析
Sep 07 Python
微信跳一跳python自动代码解读1.0
Jan 12 Python
用Python下载一个网页保存为本地的HTML文件实例
May 21 Python
基于python实现学生管理系统
Oct 17 Python
Python使用pandas对数据进行差分运算的方法
Dec 22 Python
Python中的支持向量机SVM的使用(附实例代码)
Jun 26 Python
python几种常用功能实现代码实例
Dec 25 Python
tensorflow实现读取模型中保存的值 tf.train.NewCheckpointReader
Feb 10 Python
Python如何实现定时器功能
May 28 Python
详解Go语言运用广度优先搜索走迷宫
常用的Python代码调试工具总结
Django+Celery实现定时任务的示例
Python django中如何使用restful框架
Python基础之变量的相关知识总结
Jun 23 #Python
浅谈Python数学建模之固定费用问题
浅谈Python数学建模之整数规划
You might like
40年前的这部特摄片恐龙特级克塞号80后的共同回忆
2020/03/08 日漫
ThinkPHP的RBAC(基于角色权限控制)深入解析
2013/06/17 PHP
PHP中SESSION的注销与清除
2015/04/16 PHP
php编写的抽奖程序中奖概率算法
2015/05/14 PHP
详谈配置phpstorm完美支持Codeigniter(CI)代码自动完成(代码提示)
2017/04/07 PHP
PHP 范围解析操作符(::)用法分析【访问静态成员和类常量】
2020/04/14 PHP
JavaScript 学习笔记(四)
2009/12/31 Javascript
通过jQuery源码学习javascript(二)
2012/12/27 Javascript
JavaScript中的this关键字介绍与使用实例
2013/06/21 Javascript
JavaScript加入收藏夹功能(兼容IE、firefox、chrome)
2014/05/05 Javascript
Javascript封装DOMContentLoaded事件实例
2014/06/12 Javascript
js实现在同一窗口浏览图片
2014/09/17 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
2014/10/16 Javascript
javascript关于open.window子页面执行完成后刷新父页面的问题分析
2015/04/27 Javascript
纯js代码实现简单计算器
2015/12/02 Javascript
浅析AMD CMD CommonJS规范--javascript模块化加载学习心得总结
2016/03/16 Javascript
JavaScript学习小结之被嫌弃的eval函数和with语句实例详解
2016/08/01 Javascript
nodejs开发——express路由与中间件
2017/03/24 NodeJs
Vue开发中整合axios的文件整理
2017/04/29 Javascript
Python实现去除列表中重复元素的方法小结【4种方法】
2018/04/27 Python
Python理解递归的方法总结
2019/01/28 Python
pandas 如何分割字符的实现方法
2019/07/29 Python
django下创建多个app并设置urls方法
2020/08/02 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
python 基于opencv实现高斯平滑
2020/12/18 Python
python装饰器代码深入讲解
2021/03/01 Python
Mountain Warehouse波兰官方网站:英国户外品牌
2019/08/29 全球购物
商得四方公司面试题(gid+)
2014/04/30 面试题
小学生母亲节演讲稿
2014/05/07 职场文书
办公室年度工作总结2015
2015/05/21 职场文书
正规欠条模板
2015/07/03 职场文书
pytorch MSELoss计算平均的实现方法
2021/05/12 Python
Python中的np.argmin()和np.argmax()函数用法
2021/06/02 Python
Golang 语言控制并发 Goroutine的方法
2021/06/30 Golang
四十九个javascript小知识实用技巧
2021/11/20 Javascript
阿里云ECS云服务器快照的概念以及如何使用
2022/04/21 Servers