python,进程和线程
进程:对于操作系统来说,一个任务就是一个进程(Process)
比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
线程:在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)
比如Word,它可以同时进行打字、拼写检查、打印等事情。真正地同时执行多线程需要多核CPU才可能实现。
多任务的实现有3种方式:
- 多进程模式;
- 多线程模式;
- 多进程+多线程模式。
线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。
多进程和多线程的程序涉及到同步、数据共享的问题,编写起来更复杂。
多进程
Unix/Linux操作系统提供了一个fork()
系统调用。普通的函数调用,调一次返一次,但fork()
调一次返两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),分别在父进程和子进程内返回。
子进程永远返回0
,而父进程返回子进程的ID。因为一个父进程可以fork出很多子进程,所以,父进程要记下子进程的ID,子进程调用getppid()
拿到父进程的ID。
# Python的os
模块封装了常见的系统调用,其中就包括fork
,可以在Python程序中轻松创建子进程: import osprint('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0:print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else:print('I (%s) just created a child process (%s).' % (os.getpid(), pid))#结果 Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.
由于Mac系统是基于BSD(Unix的一种)内核,所以,在Mac下运行是没有问题的,在Windows上,使用
multiprocessing
multiprocessing模块提供了一个Process类来代表一个进程对象
from multiprocessing import Process import os# 子进程要执行的代码 def run_proc(name):print('Run child process %s (%s)...' % (name, os.getpid()))if __name__=='__main__':print('Parent process %s.' % os.getpid())#childp = Process(target=run_proc, args=('test',))p.start()#join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步 p.join()#结果如下 Parent process 928. Run child process test (929)...
如果要启动大量的子进程,可以用进程池的方式批量创建子进程
Pool
from multiprocessing import Pool import os, time, randomdef long_time_task(name):print('Run task %s (%s)...' % (name, os.getpid()))start = time.time()time.sleep(random.random() * 3)end = time.time()print('Task %s runs %0.2f seconds.' % (name, (end - start)))if __name__=='__main__':print('Parent process %s.' % os.getpid())#同时跑进程的个数,Pool的默认大小是CPU的核数p = Pool(4)for i in range(5):p.apply_async(long_time_task, args=(i,))print('Waiting for all subprocesses done...')p.close()#等待所有子进程执行完毕,用之前必用close p.join()print('All subprocesses done.')#结果 Parent process 669. Waiting for all subprocesses done... Run task 0 (671)... Run task 1 (672)... Run task 2 (673)... Run task 3 (674)... Task 2 runs 0.14 seconds. Run task 4 (673)... Task 1 runs 0.27 seconds. Task 3 runs 0.86 seconds. Task 0 runs 1.41 seconds. Task 4 runs 1.91 seconds. All subprocesses done.
子进程
很多时候,子进程并不是自身,而是一个外部进程。我们创建了子进程后,还需要控制子进程的输入和输出。
subprocess
import subprocessprint('$ nslookup www.python.org') r = subprocess.call(['nslookup', 'www.python.org']) print('Exit code:', r)#运行结果: $ nslookup www.python.org Server: 192.168.19.4 Address: 192.168.19.4#53 Non-authoritative answer: www.python.org canonical name = python.map.fastly.net. Name: python.map.fastly.net Address: 199.27.79.223Exit code: 0#如果子进程还需要输入,则可以通过communicate()方法输入 import subprocessprint('$ nslookup') p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate(b'set q=mx\npython.org\nexit\n') print(output.decode('utf-8')) print('Exit code:', p.returncode)#多进程 阅读: 209404 要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识。Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程:import osprint('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0:print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else:print('I (%s) just created a child process (%s).' % (os.getpid(), pid)) 运行结果如下:Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876. 由于Windows没有fork调用,上面的代码在Windows上无法运行。由于Mac系统是基于BSD(Unix的一种)内核,所以,在Mac下运行是没有问题的,推荐大家用Mac学Python!有了fork调用,一个进程在接到新任务时就可以复制出一个子进程来处理新任务,常见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。multiprocessing如果你打算编写多进程的服务程序,Unix/Linux无疑是正确的选择。由于Windows没有fork调用,难道在Windows上无法用Python编写多进程的程序?由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:from multiprocessing import Process import os# 子进程要执行的代码 def run_proc(name):print('Run child process %s (%s)...' % (name, os.getpid()))if __name__=='__main__':print('Parent process %s.' % os.getpid())p = Process(target=run_proc, args=('test',))print('Child process will start.')p.start()p.join()print('Child process end.') 执行结果如下:Parent process 928. Process will start. Run child process test (929)... Process end. 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。Pool如果要启动大量的子进程,可以用进程池的方式批量创建子进程:from multiprocessing import Pool import os, time, randomdef long_time_task(name):print('Run task %s (%s)...' % (name, os.getpid()))start = time.time()time.sleep(random.random() * 3)end = time.time()print('Task %s runs %0.2f seconds.' % (name, (end - start)))if __name__=='__main__':print('Parent process %s.' % os.getpid())p = Pool(4)for i in range(5):p.apply_async(long_time_task, args=(i,))print('Waiting for all subprocesses done...')p.close()p.join()print('All subprocesses done.') 执行结果如下:Parent process 669. Waiting for all subprocesses done... Run task 0 (671)... Run task 1 (672)... Run task 2 (673)... Run task 3 (674)... Task 2 runs 0.14 seconds. Run task 4 (673)... Task 1 runs 0.27 seconds. Task 3 runs 0.86 seconds. Task 0 runs 1.41 seconds. Task 4 runs 1.91 seconds. All subprocesses done. 代码解读:对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。请注意输出的结果,task 0,1,2,3是立刻执行的,而task 4要等待前面某个task完成后才执行,这是因为Pool的默认大小在我的电脑上是4,因此,最多同时执行4个进程。这是Pool有意设计的限制,并不是操作系统的限制。如果改成:p = Pool(5) 就可以同时跑5个进程。由于Pool的默认大小是CPU的核数,如果你不幸拥有8核CPU,你要提交至少9个子进程才能看到上面的等待效果。子进程很多时候,子进程并不是自身,而是一个外部进程。我们创建了子进程后,还需要控制子进程的输入和输出。subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。下面的例子演示了如何在Python代码中运行命令nslookup www.python.org,这和命令行直接运行的效果是一样的:import subprocessprint('$ nslookup www.python.org') r = subprocess.call(['nslookup', 'www.python.org']) print('Exit code:', r) 运行结果:$ nslookup www.python.org Server: 192.168.19.4 Address: 192.168.19.4#53 Non-authoritative answer: www.python.org canonical name = python.map.fastly.net. Name: python.map.fastly.net Address: 199.27.79.223Exit code: 0 如果子进程还需要输入,则可以通过communicate()方法输入:import subprocessprint('$ nslookup') p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate(b'set q=mx\npython.org\nexit\n') print(output.decode('utf-8')) print('Exit code:', p.returncode) #上面的代码相当于在命令行执行命令nslookup,然后手动输入: set q=mx python.org exit#结果 $ nslookup Server: 192.168.19.4 Address: 192.168.19.4#53 Non-authoritative answer: python.org mail exchanger = 50 mail.python.org.Authoritative answers can be found from: mail.python.org internet address = 82.94.164.166 mail.python.org has AAAA address 2001:888:2000:d::a6Exit code: 0
进程间通信
Process
之间肯定是需要通信的,Python的multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据。
以Queue
为例,在父进程中创建两个子进程,一个往Queue
里写数据,一个从Queue
里读数据:
from multiprocessing import Process, Queue import os, time, random# 写数据进程执行的代码: def write(q):print('Process to write: %s' % os.getpid())for value in ['A', 'B', 'C']:print('Put %s to queue...' % value)q.put(value)time.sleep(random.random())# 读数据进程执行的代码: def read(q):print('Process to read: %s' % os.getpid())while True:value = q.get(True)print('Get %s from queue.' % value)if __name__=='__main__':# 父进程创建Queue,并传给各个子进程:q = Queue()pw = Process(target=write, args=(q,))pr = Process(target=read, args=(q,))# 启动子进程pw,写入: pw.start()# 启动子进程pr,读取: pr.start()# 等待pw结束: pw.join()# pr进程里是死循环,无法等待其结束,只能强行终止: pr.terminate()#运行结果如下: Process to write: 50563 Put A to queue... Process to read: 50564 Get A from queue. Put B to queue... Get B from queue. Put C to queue... Get C from queue.
转载于:https://www.cnblogs.com/xiexiaoxiao/p/7056508.html
python,进程和线程相关推荐
- python进程和线程_Python进程与线程知识
好程序员Python 培训分享进程与线程知识 , Python 开发语言现在已经是被大家非常看中的编程语言了,本篇文章给读者们分享一下 Python 进程与线程知识小结,本篇文章具有一定的参考借鉴价值 ...
- python进程和线程
python 进程和线程 概念 GIL: 全局解释锁,解决了不同线程同时访问统一资源时,数据保护问题.python 虽然是多线程,但是因为GIL,实际上是是单线程,由CPU轮询,假线程.(一个线程运行 ...
- python进程与线程_Python进程与线程知识
Python培训分享进程与线程知识,Python开发语言现在已经是被大家非常看中的编程语言了,本篇文章给读者们分享一下Python进程与线程知识小结,本篇文章具有一定的参考借鉴价值,感兴趣的小伙伴来了 ...
- python 进程,线程,协程篇
python 进程,线程,协程篇 ssh 线程 进程 线程,进程区别 threading 模块,两种调用方式 python GIL全局解释器锁(Global Interpreter Lock) Joi ...
- Python进程和线程保姆式教学,1个台机子多只手干活的秘籍
进程线程有多重要?刚开始学Python的时候你可能还没有感觉到,因为你写的代码从上到下执行一遍就可以了,但实际上这很初级,实际开发写项目的时候,为了充分利用电脑配置来加快程序进度,我们往往会用到多进程 ...
- Python进程、线程、协程详解
进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...
- python进程、线程的学习心得
什么是多线程竞争? 线程不是独立的,同一个进程里的线程,线程间的数据是共享的,多线程操作时,容易造成数据的混乱,线程不安全. 如何解决? 互斥锁. 好处:能够保证某段关键代码执行时,只有一个线程操作, ...
- python进程、线程、协程
基本观点: 1.一个python进程一个GIL(全局锁),每个线程需要获取这个锁才能执行. 2.cpu密集型的程序,使用多进程. 3.IO密集型的程序,多线程可能会比多进程快. 4.多核cpu执行多进 ...
- python 进程和线程
python中的进程.线程(threading.multiprocessing.Queue.subprocess) Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就 ...
- python 进程与线程(理论部分)
一.理论部分 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的 ...
最新文章
- 自定义本地音乐播放器
- Linux运维课程-Mysql之复制(2)
- java实现将一个正整数分解质因数,Java将一个正整数分解质因数
- SAP 银行主数据 SWIFT 码
- freeswitch 改用mysql_freeswitch和Mysql
- 龙格库塔(Runge-Kutta)法求四元数微分方程
- 20不会电脑可以学计算机吗,20个关于计算机二级考试的技巧,不会不行!
- 【预测模型-RF预测】基于随机森林算法实现数据回归预测附matlab代码
- L2到L4的泊车辅助系统---APA自动泊车、RPA远程遥控泊车、自学习泊车、AVP自动代客泊车
- Mac系统查看端口占用的进程
- JDK源码解析---Short
- 状态机(FSM)的分类描述
- python+selenium移动滑块代码【杭州多测师_王sir】【杭州多测师】
- These Days
- 年会抽奖源码html js,js年会抽奖程序
- python表格处理实例_python列表格
- osgEarth示例分析——osgearth_minimap
- Vue 项目的成功发布和部署
- 每日一记:zabbix日志报错cannot process item fra[usable,pct] trap: item type 15 cannot be used with traps
- 【rmzt】XP系统动漫桌面主题下载
热门文章
- oracle常见等待事件,必看干货 | Oracle 常见的等待事件说明(下)
- SQLi LABS Less 27 联合注入+报错注入+布尔盲注+时间盲注
- kylin操作系统是什么
- 对象不支持属性或方法dbzz.html,JavaScript 中 setTimeout()的用法 ZZ
- [SDOI2011]工作安排 BZOJ2245
- windows本地凭据备份与还原
- mybatis报错(三)报错Result Maps collection does not contain value for java.lang.Integer解决方法...
- lazyload 加载
- MVC LinqToSql Json DbComparisonExpression 需要具有可比较类型的参数。
- 会计基础第二次模拟题(3)