Python说文解字_Python之多任务_03
问:线程学完了,现在我们开始学习进程了吧?
答:是的。前面说到线程就是我们的手,我们现在可以学习一下我们的“胳膊”了。
我们有了多线程,为什么还要学习多进程呢?这是因为在Python当中有一把GIL锁的存在,比如某些耗CPU的运算的时候,我们可以运行多进程多个CPU并发的操作进行操作。对于IO操作来说,我们的瓶颈不在于我们的CPU因此我们用多线程操作。进程切换操作不是轻量级的。
我们首先举例一个数据密集型的操作,来计算斐波那契数列:
from concurrent.futures import ThreadPoolExecutor,as_completed
from concurrent.futures import ProcessPoolExecutor
import time def fib(n):
if n<=:
return
return fib(n-) + fib(n-) if __name__ == '__main__':
with ThreadPoolExecutor() as executor:
all_task = [executor.submit(fib,(num)) for num in range(,)]
start_time = time.time()
for future in as_completed(all_task):
data = future.result()
print("get result:= {}".format(data))
print("multithread last time is {}".format(time.time()-start_time)) with ProcessPoolExecutor() as executor:
all_task = [executor.submit(fib,(num)) for num in range(,)]
start_time = time.time()
for future in as_completed(all_task):
data = future.result()
print("get result:= {}".format(data))
print("multiprocess last time is {}".format(time.time()-start_time))
#
# multithread last time is 43.156678199768066
# multiprocess last time is 27.62783455848694
我们明显看到多进程比多线程快。
我们在以一个IO操作来进行对比:
from concurrent.futures import ThreadPoolExecutor,as_completed
from concurrent.futures import ProcessPoolExecutor
import time def random_sleep(n):
time.sleep(n)
return n if __name__ == '__main__':
with ThreadPoolExecutor() as executor:
all_task = [executor.submit(random_sleep,(num)) for num in []*]
start_time = time.time()
for future in as_completed(all_task):
data = future.result()
print("get result:= {}".format(data))
print("multithread last time is {}".format(time.time()-start_time)) with ProcessPoolExecutor() as executor:
all_task = [executor.submit(random_sleep,(num)) for num in []*]
start_time = time.time()
for future in as_completed(all_task):
data = future.result()
print("get result:= {}".format(data))
print("multiprocess last time is {}".format(time.time()-start_time))
#
# multithread last time is 20.035860300064087
# multiprocess last time is 20.641016483306885
正式进入我们的进程操作:
import os
import time
# fork只能用于linux下面
pid = os.fork()
print("bobby")
if pid == :
print("子进程{},父进程是{}".format(os.getpid(),os.getppid()))
else:
print("我是父进程:{}".format(pid)) time.sleep()
这段代码只能在Linux下运行。我们发现的问题是如果主进程结束了,子进程还是会运行的。
问:进程如何进行编程?
答:我们懂了线程的编程,进程的编程会变得非常的简单。多余的内容就不再讲解,我们讲解一些不同的包,其实这些包的应用也是跟进程差不多的。
multiprocessing
import multiprocessing
import time
def get_html(n):
time.sleep(n)
return n if __name__ == '__main__':
progress = multiprocessing.Process(target=get_html,args=(,))
progress.start()
progress.join()
我们还可以直接获取进程的pid和ppid。
其他和我们多线程差不都就不详解了。
使用进程池:
进程池:Pool和ProcessPoolExecutor。后那个跟线程一样。我们单独说一下Pool这个进程池。
import multiprocessing
import time
from multiprocessing import Pool def get_html(n):
time.sleep(n)
return n if __name__ == '__main__':
progress = multiprocessing.Process(target=get_html,args=(,))
progress.start()
progress.join()
pool = Pool(multiprocessing.cpu_count())
print(multiprocessing.cpu_count())
result = pool.apply_async(get_html,args=(,))
pool.close()
注意最后要关闭线程池。详细的关于线程池的代码可以参照这里:https://www.cnblogs.com/noah0532/p/10938771.html
特别要说明的是有两个方法:imap 和 imap_unordered(这个是谁先完成先打印谁)
for result in pool.imap(get_html,[,,]):
进程间的通信:
进程间的通信和线程间的通信有一样的也有不一样的地方,比如锁就不能使用了。
举一个简单的例子:用队列进行通信
from multiprocessing import Process,Queue
# from queue import Queue # 这个queue就不能用了
import time def producer(queue):
queue.put("a")
time.sleep() def consumer(queue):
time.sleep()
data = queue.get()
print(data) if __name__ == '__main__':
queue = Queue()
my_producer = Process(target=producer,args=(queue,))
my_consumer = Process(target=consumer, args=(queue,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
在多进程的编程中不能用之前的queue了,带用multiprocessing里面的queue,这一带你要注意
我们再举一个共享变量的例子:
from multiprocessing import Process
import time def producer(a):
a +=
time.sleep() def consumer(a):
time.sleep()
print(a) if __name__ == '__main__':
a =
my_producer = Process(target=producer,args=(a,))
my_consumer = Process(target=consumer, args=(a,))
my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
我们发现我们的全局变量不能用了,正如我们前面说的,我们再进程中每一块的变量是单独的,不能共享的。
另外multiprocessing中的queue也不能用在进程池当中。如果我们想在进程当中应用就带用Manager当中的Queue
from multiprocessing import Process,Queue,Manager,Pool
import time def producer(queue):
queue.put("a")
time.sleep() def consumer(queue):
time.sleep()
data = queue.get()
print(data) if __name__ == '__main__':
queue = Manager().Queue()
pool = Pool() pool.apply_async(producer,args=(queue,))
pool.apply_async(consumer, args=(queue,)) pool.close()
pool.join()
另外,我们还可以通过我们的pipe管道来进行通讯,但是Pipe只能使用两个进程间的通信,如果是两个交换pipe的性能比queue高
from multiprocessing import Process,Queue,Manager,Pool,Pipe
import time def producer(pipe):
pipe.send("bobby") def consumer(pipe):
print(pipe.recv()) if __name__ == '__main__':
# pipe只能用于两个进程间的通讯
receive_pipe,send_pipe = Pipe()
my_producer = Process(target=producer,args=(send_pipe,))
my_consumer = Process(target=consumer, args=(receive_pipe,)) my_producer.start()
my_consumer.start()
my_producer.join()
my_consumer.join()
重点:进程间的共享内存操作:Manager().dict(),array()....常用的数据类型都有。
from multiprocessing import Process,Queue,Manager,Pool,Pipe def add_data(p_dict,key,value):
p_dict[key] = value if __name__ == '__main__':
progress_dict = Manager().dict() first_progess = Process(target=add_data,args=(progress_dict,"bobby1",))
second_progess = Process(target=add_data, args=(progress_dict, "bobby1", )) first_progess.start()
second_progess.start()
first_progess.join()
second_progess.join() print(progress_dict)
# {'bobby1': }
Python说文解字_Python之多任务_03的更多相关文章
- Python说文解字_Python之多任务_01
Python 之 多任务: Python之多任务是现在多任务编程运用Python语言为载体的一种体现.其中涵盖:进程.线程.并发等方面的内容,以及包括近些年在大数据运算.人工智能领域运用强大的GPU运 ...
- Python说文解字_Python之多任务_05
问:在Py3.5之前yield表现非常好,在Py3.5之后为了将予以变得更加明确,就引入了async和await关键词用于定义原生的协议. 答:async和await原生协程: async def d ...
- Python说文解字_Python之多任务_02
第三部分:Semaphore控制进入数量的锁 有时候可能需要运行多个工作线程同时访问一个资源,但要限制总数.例如,连接池支持同时连接,但是数目可能是固定的,或者一个网络应用可能支持固定数据的并发下载. ...
- Python说文解字_Python之多任务_04
问:并发.并行.同步.异步.阻塞.非阻塞 答: 并发.并行: 并发是指一个时间段内(不是指的时间点),有几个程序在同一个CPU上运行,但是任意时刻只有一个程序在CPU上运行.对人类的时钟来说1秒钟能干 ...
- Python说文解字_详解元类
1.深入理解一切接对象: 1.1 什么是类和对象? 首先明白元类之前要明白什么叫做类.类是面向对象object oriented programming的重要概念.在面向对象中类和对象是最基本的两个概 ...
- Python说文解字_杂谈05
1. isinstance和type: is和==符号,is指的是内存地址,是不是一个对象,ID知否相同 集成链 class A: pass class B(A): pass b = B() prin ...
- Python说文解字_杂谈09
1. 元类编程代码分析: import numbers class Field: pass class IntField(Field): # 数据描述符: # 初始化 def __init__(sel ...
- Python说文解字_杂谈08
1. Python变量到底是什么? Python和Java中的变量本质不一样,python的变量实质是一个指针 int str,便利贴 a = 1 # 1. a贴在1上面 # 2. 它的过程是先生成对 ...
- Python说文解字_杂谈07
1. 深入dict from collections.abc import Mapping,MutableMapping # dict 属于mapping类型 a = {} print(isinsta ...
随机推荐
- tools.lombok
@Slf4j @Data @Accessors @Builder
- 1.HDFS分布式文件系统
HDFS概述及设计目标 如果让我们自己设计一个分布式文件存储系统,怎么做? HDFS设计目标 非常巨大的分布式文件系统 运行在普通廉价的硬件上 易扩展,为用户提供性能不错的文件存储系统 HDFS架构 ...
- pyhton pandas数据分析基础入门(一文看懂pandas)
//2019.07.17 pyhton中pandas数据分析基础入门(一文看懂pandas), 教你迅速入门pandas数据分析模块(后面附有入门完整代码,可以直接拷贝运行,含有详细的代码注释,可以轻 ...
- Codeforces1243C Tile Painting
原题面:https://codeforces.com/contest/1243/problem/C 题目大意:给定数字n,有n个方块,第i个和第j个之间的距离(abs(i-j))如果是n的因子,那么第 ...
- [BJDCTF2020]EasySearch
0x00 知识点 Apache SSI 远程命令执行漏洞 链接: https://www.cnblogs.com/yuzly/p/11226439.html 当目标服务器开启了SSI与CGI支持,我们 ...
- Q 格式使用总结
注意 16位有符号数 表示的范围是 -32768~32767 假如 整形数在内存中以源码的形式存放, 则0000 0000 0000 0000 表示正整数0 则 1000 0000 0000 0000 ...
- 云时代架构阅读笔记五——Java内存模型详解(一)
什么是Java内存模型 Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的访问差异,以实现让Java程序在各种平台下都能达到一致 ...
- HDU 3397 线段树 双懒惰标记
这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全 ...
- vue学习(七)refs的使用
ref的使用只有在特殊的情况下使用 1.如果给标签添加ref,获取的就是真实的DOM节点2. 如果给子组件添加ref,获取的就是当前的子组件对象 例子: <div id="app&qu ...
- 基于Ambari的WebUI部署Hive服务
基于Ambari的WebUI部署Hive服务 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.部署Ambari服务 博主推荐阅读: https://www.cnblogs.com ...