详解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模块开发的多线程豆瓣小站mp3下载器
Jan 16 Python
Python中的fileinput模块的简单实用示例
Jul 09 Python
Python Tkinter模块实现时钟功能应用示例
Jul 23 Python
python查看模块安装位置的方法
Oct 16 Python
pytorch使用Variable实现线性回归
May 21 Python
python实现复制大量文件功能
Aug 31 Python
Python3监控windows,linux系统的CPU、硬盘、内存使用率和各个端口的开启情况详细代码实例
Mar 18 Python
解决pyqt5异常退出无提示信息的问题
Apr 08 Python
Python HTMLTestRunner测试报告view按钮失效解决方案
May 25 Python
新版Pycharm中Matplotlib不会弹出独立的显示窗口的问题
Jun 02 Python
基于Python正确读取资源文件
Sep 14 Python
Python绘制地图神器folium的新人入门指南
May 23 Python
详解Go语言运用广度优先搜索走迷宫
常用的Python代码调试工具总结
Django+Celery实现定时任务的示例
Python django中如何使用restful框架
Python基础之变量的相关知识总结
Jun 23 #Python
浅谈Python数学建模之固定费用问题
浅谈Python数学建模之整数规划
You might like
模板引擎smarty工作原理以及使用示例
2014/05/25 PHP
PHP实现从远程下载文件的方法
2015/03/12 PHP
php登录超时检测功能实例详解
2017/03/21 PHP
PHP实现的观察者模式实例
2017/06/21 PHP
php图片合成方法(多张图片合成一张)
2017/11/25 PHP
laravel5.6实现数值转换
2019/10/23 PHP
ASP.NET jQuery 实例18 通过使用jQuery validation插件校验DropDownList
2012/02/03 Javascript
jQuery点击弹出下拉菜单的小例子
2013/08/01 Javascript
利用jquery.qrcode在页面上生成二维码且支持中文
2014/02/12 Javascript
javascript常用经典算法实例详解
2015/11/25 Javascript
javascript实现PC网页里的拖拽效果
2016/03/14 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
Jquery实现select multiple左右添加和删除功能的简单实例
2016/05/26 Javascript
JavaScript数据结构学习之数组、栈与队列
2017/05/02 Javascript
解决angularjs WdatePicker ng-model的问题
2018/09/13 Javascript
vue过滤器用法实例分析
2019/03/15 Javascript
vue实现菜单切换功能
2019/05/08 Javascript
JavaScript函数式编程(Functional Programming)箭头函数(Arrow functions)用法分析
2019/05/22 Javascript
微信小程序实现卡片层叠滑动效果
2019/06/21 Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
2019/07/20 Javascript
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
javascript 数组(list)添加/删除的实现
2020/12/17 Javascript
jquery自定义组件实例详解
2020/12/31 jQuery
简单谈谈python中的lambda表达式
2018/01/19 Python
python使用json序列化datetime类型实例解析
2018/02/11 Python
Python字符串的常见操作实例小结
2019/04/08 Python
python 错误处理 assert详解
2020/04/20 Python
Python3基于plotly模块保存图片表格
2020/08/03 Python
css3动画效果抖动解决方法
2018/09/03 HTML / CSS
工作中的自我评价如何写好
2013/10/28 职场文书
弘扬职业精神演讲稿
2014/03/20 职场文书
个人函授自我鉴定
2014/03/25 职场文书
见习报告格式范文
2014/11/08 职场文书
2015年幼儿园卫生保健工作总结
2015/05/12 职场文书
《鸟的天堂》教学反思
2016/02/19 职场文书
标会主持词应该怎么写?
2019/08/15 职场文书