进程:对于操作系统来说,一个任务就是一个进程(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模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

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,进程和线程相关推荐

  1. python进程和线程_Python进程与线程知识

    好程序员Python 培训分享进程与线程知识 , Python 开发语言现在已经是被大家非常看中的编程语言了,本篇文章给读者们分享一下 Python 进程与线程知识小结,本篇文章具有一定的参考借鉴价值 ...

  2. python进程和线程

    python 进程和线程 概念 GIL: 全局解释锁,解决了不同线程同时访问统一资源时,数据保护问题.python 虽然是多线程,但是因为GIL,实际上是是单线程,由CPU轮询,假线程.(一个线程运行 ...

  3. python进程与线程_Python进程与线程知识

    Python培训分享进程与线程知识,Python开发语言现在已经是被大家非常看中的编程语言了,本篇文章给读者们分享一下Python进程与线程知识小结,本篇文章具有一定的参考借鉴价值,感兴趣的小伙伴来了 ...

  4. python 进程,线程,协程篇

    python 进程,线程,协程篇 ssh 线程 进程 线程,进程区别 threading 模块,两种调用方式 python GIL全局解释器锁(Global Interpreter Lock) Joi ...

  5. Python进程和线程保姆式教学,1个台机子多只手干活的秘籍

    进程线程有多重要?刚开始学Python的时候你可能还没有感觉到,因为你写的代码从上到下执行一遍就可以了,但实际上这很初级,实际开发写项目的时候,为了充分利用电脑配置来加快程序进度,我们往往会用到多进程 ...

  6. Python进程、线程、协程详解

    进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...

  7. python进程、线程的学习心得

    什么是多线程竞争? 线程不是独立的,同一个进程里的线程,线程间的数据是共享的,多线程操作时,容易造成数据的混乱,线程不安全. 如何解决? 互斥锁. 好处:能够保证某段关键代码执行时,只有一个线程操作, ...

  8. python进程、线程、协程

    基本观点: 1.一个python进程一个GIL(全局锁),每个线程需要获取这个锁才能执行. 2.cpu密集型的程序,使用多进程. 3.IO密集型的程序,多线程可能会比多进程快. 4.多核cpu执行多进 ...

  9. python 进程和线程

    python中的进程.线程(threading.multiprocessing.Queue.subprocess) Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就 ...

  10. python 进程与线程(理论部分)

    一.理论部分 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的 ...

最新文章

  1. 自定义本地音乐播放器
  2. Linux运维课程-Mysql之复制(2)
  3. java实现将一个正整数分解质因数,Java将一个正整数分解质因数
  4. SAP 银行主数据 SWIFT 码
  5. freeswitch 改用mysql_freeswitch和Mysql
  6. 龙格库塔(Runge-Kutta)法求四元数微分方程
  7. 20不会电脑可以学计算机吗,20个关于计算机二级考试的技巧,不会不行!
  8. 【预测模型-RF预测】基于随机森林算法实现数据回归预测附matlab代码
  9. L2到L4的泊车辅助系统---APA自动泊车、RPA远程遥控泊车、自学习泊车、AVP自动代客泊车
  10. Mac系统查看端口占用的进程
  11. JDK源码解析---Short
  12. 状态机(FSM)的分类描述
  13. python+selenium移动滑块代码【杭州多测师_王sir】【杭州多测师】
  14. These Days
  15. 年会抽奖源码html js,js年会抽奖程序
  16. python表格处理实例_python列表格
  17. osgEarth示例分析——osgearth_minimap
  18. Vue 项目的成功发布和部署
  19. 每日一记:zabbix日志报错cannot process item fra[usable,pct] trap: item type 15 cannot be used with traps
  20. 【rmzt】XP系统动漫桌面主题下载

热门文章

  1. oracle常见等待事件,必看干货 | Oracle 常见的等待事件说明(下)
  2. SQLi LABS Less 27 联合注入+报错注入+布尔盲注+时间盲注
  3. kylin操作系统是什么
  4. 对象不支持属性或方法dbzz.html,JavaScript 中 setTimeout()的用法 ZZ
  5. [SDOI2011]工作安排 BZOJ2245
  6. windows本地凭据备份与还原
  7. mybatis报错(三)报错Result Maps collection does not contain value for java.lang.Integer解决方法...
  8. lazyload 加载
  9. MVC LinqToSql Json DbComparisonExpression 需要具有可比较类型的参数。
  10. 会计基础第二次模拟题(3)