GIL (global interpreter lock)全局解释器锁
基于cpython的介绍:
python中的一个线程是对应于c语言中的一个线程,python在早期的时候为了简单,会在解释器上加一把非常大的锁,允许我们同一时刻只有一个线程运行在一个cpu上执行字节码。在某种程度上保证了我们的线程是安全的。它无法将多个线程映射到多个cpu上执行,使得我们无法利用多核优势。
gil使得同一时刻只有一个线程在一个cpu上执行字节码
python现在正在努力的去掉gil,像pypy是去gil的.因为cpython当中的许多第三方包使用gil的,所以短期类gil是不太可能被去掉的。
那么是不是说在一个时刻只有一个线程运行在我们的cpu上,就意味着我们在使用多线程编码的时候就是安全的呢?就不用去考虑线程之间的同步呢?实际上不是的。因为gil在某些情况下是会被释放的。gil的释放在python2和python3还有区别的。
gil的释放:
1.gil会根据执行的字节码行数以及时间片释放gil
2.gil还会在遇到io操作的时候主动释放
所以python在io操作的时候,多线程编程就变得非常重要了。
# import dis
# def add(a):
# a=a+1
# return a
# #我们可以对它进行反编译的
# print(dis.dis(add))
'''
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter11/pythonGIL.py
3 0 LOAD_FAST 0 (a)
2 LOAD_CONST 1 (1)
4 BINARY_ADD
6 STORE_FAST 0 (a)
4 8 LOAD_FAST 0 (a)
10 RETURN_VALUE
None
'''
total=0
def add():
global total
for i in range(1000000):
total+=1
def desc():
global total
for i in range(1000000):
total-=1
import threading
thread1=threading.Thread(target=add)
thread2=threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)
多线程编程
操作系统能够调度的最小单元是线程,在最开始的时候操作系统能够调度的最小单元实际上是进程,但是因为进程对于系统的资源消耗非常大,所以后期就演变出了线程。线程实际上是依赖于进程的。如在windows任务管理器中会看到许多的进程,如下图:
对于操作系统来说能够调度的做小单元是线程。
多线程编程:
1.通过Thread类实例化
# 对于io操作来说,多线程和多进程差别不大
import time
import threading
#1.通过Thread类实例化
def get_detail_html(url):
print("get detail html started")
time.sleep(2)
print("get detail html end")
def get_detail_url(url):
print("get detail url started")
time.sleep(4)
print("get detail url end")
if __name__=="__main__":
thread1=threading.Thread(target=get_detail_html,args={"",})
thread2 = threading.Thread(target=get_detail_url, args={"",})
#设置子进程为守护线程 当主线程退出的时候,子线程也会被关掉。
# thread1.setDaemon(True)
thread2.setDaemon(True)
start_time=time.time()
thread1.start()
thread2.start()
#那么如何使得在两个线程运行完成之后再执行主线程呢
thread1.join()
thread2.join()
'''
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter11/python_thread.py
get detail html started
get detail url started
get detail html end
get detail url end
last time: 4.0012288093566895
在加入线程阻塞之后,主线程会等待两个子线程执行完成之后才开始执行,而两个子线程
运行所用的时间并不是顺序运行的时间,而是在一定程度的并行运行,因此是花费了线程
2所用的时间。
'''
'''
虽然在这个python脚本当中创建了2个线程,但是实际上一共有3个线程
第三个线程就是我们的python程序,即所说的主线程。
'''
print("last time: {}".format(time.time()-start_time))
2.通过继承Thread来实现多线程 适用于复杂的场景
import time
import threading
class GetDetailHtml(threading.Thread):
#重载init方法
def __init__(self,name):
super().__init__(name=name)
#重载run方法
def run(self):
print("get detail html started")
time.sleep(2)
print("get detail html end")
class GetDetailUrl(threading.Thread):
# 重载init方法
def __init__(self,name):
super().__init__(name=name)
# 重载run方法
def run(self):
print("get detail url started")
time.sleep(4)
print("get detail url end")
#通过这两个类的实例完成我们的多线程
if __name__=="__main__":
thread1=GetDetailHtml("getdetailhtml")
thread2= GetDetailUrl("getdetailurl")
# thread1.setDaemon(True)
thread2.setDaemon(True)
start_time=time.time()
thread1.start()
thread2.start()
#那么如何使得在两个线程运行完成之后再执行主线程呢
thread1.join()
thread2.join()
print("last time: {}".format(time.time() - start_time))
线程间通信
1.线程间共享变量
import time
import threading
from pythonHight.chapter11.variables import detail_url_list
from pythonHight.chapter11 import variables
#1.通过Thread类实例化
#爬取文章详情页
def get_detail_html():
detail_url_list=variables.detail_url_list
# while True:
if len(detail_url_list):
# global detail_url_list
url=detail_url_list.pop()
# for url in detail_url_list:
print("get detail html started")
time.sleep(0.5)
print("get detail html end")
#爬取文章列表页
def get_detail_url():
# global detail_url_list
detail_url_list = variables.detail_url_list
# while True:
print("get detail url started")
time.sleep(1)
for i in range(20):
detail_url_list.append("http://www.baidu.com/{id}".format(id=i))
print("get detail url end")
#1.线程间的通信方式-共享变量
'''
线程间的变量共享涉及到很多的线程安全性问题,因为gil的原因会导致
线程在处理数据的时候没有达到预期的效果,可能会造成一定的混乱。
所以并不推荐使用共享变量进行通信,除非大家对锁比较了解
'''
#2.
if __name__=="__main__":
thread_detail_url=threading.Thread(target=get_detail_url,args=())
'''
在真正爬取url列表页面的时候是很快的,而爬取每个url里的详情速度是很慢的
如果这两个爬取方式只是分别之构建一个线程,则没有做到高并发,那么就可以
考虑构建多个爬取详情页的线程来增加并发,提高运行效率
'''
'''
直观的做法:
thread_detail_html1 = threading.Thread(target=get_detail_html, args={"", })
thread_detail_html2 = threading.Thread(target=get_detail_html, args={"", })
thread_detail_html3 = threading.Thread(target=get_detail_html, args={"", })
thread_detail_html4 = threading.Thread(target=get_detail_html, args={"", })
thread_detail_html5 = threading.Thread(target=get_detail_html, args={"", })
thread2 = threading.Thread(target=get_detail_url, args={"",})
thread_detail_url.start()
thread_detail_html1.start()
thread_detail_html2.start()
thread_detail_html3.start()
thread_detail_html4.start()
thread_detail_html5.start()
thread_detail_url.join()
thread_detail_html1.join()
thread_detail_html2.join()
thread_detail_html3.join()
thread_detail_html4.join()
thread_detail_html5.join()
'''
#其实可以使用循环来做
for i in range(10):
detail_html_thread=threading.Thread(target=get_detail_html,args=())
#设置子进程为守护线程 当主线程退出的时候,子线程也会被关掉。
# thread_detail_url.setDaemon(True)
# detail_html_thread.setDaemon(True)
# start_time=time.time()
thread_detail_url.start()
detail_html_thread.start()
#那么如何使得在两个线程运行完成之后再执行主线程呢
thread_detail_url.join()
detail_html_thread.join()
2.通过queue进行线程间同步
# 示意代码,不可运行。
#通过queue的方式来进行线程间的同步的
import time
import threading
from queue import Queue
#这里是线程安全的,为什么呢,是因为queue本身就是一个线程安全的
#在queue.get()在进行get操作的时候,他不会使得我们多个我线程去、
#操作同一个queue的时候造成数据的错误
'''
Queue是如何做到线程安全的呢,如里面的get方法是线程安全的,底层用到了
deque双端队列,它是线程安全的
'''
# 爬取文章详情页
def get_detail_html(queue):
#get方法是个阻塞的方法 如果队列为空,他会一直停在这
url = queue.get()
# for url in detail_url_list:
print("get detail html started")
time.sleep(0.5)
print("get detail html end")
# 爬取文章列表页
def get_detail_url():
while True:
print("get detail url started")
time.sleep(1)
for i in range(20):
Queue.put("http://www.baidu.com/{id}".format(id=i))
print("get detail url end")
if __name__ == "__main__":
detail_url_queue=Queue(maxsize=1000)
thread_detail_url = threading.Thread(target=get_detail_url, args=(detail_url_queue,))
for i in range(10):
detail_html_thread = threading.Thread(target=get_detail_html, args=(detail_url_queue,))
# 设置子进程为守护线程 当主线程退出的时候,子线程也会被关掉。
# thread_detail_url.setDaemon(True)
# detail_html_thread.setDaemon(True)
# start_time=time.time()
thread_detail_url.start()
detail_html_thread.start()
# 那么如何使得在两个线程运行完成之后再执行主线程呢
# thread_detail_url.join()
# detail_html_thread.join()
detail_url_queue.task_done()
detail_url_queue.join()
线程同步(Lock,RLock,Semaphores、Condition)
python中为什么需要线程同步,以及同步是什么意思?
import threading
from threading import Lock
total=0
lock=Lock()
def add():
global total
global lock
for i in range(1000000):
#获取一把锁
lock.acquire()
lock.acquire()
#不能在一把锁没有释放的情况下,又获取锁
#造成死锁
total+=1
#释放锁
lock.release()
def desc():
global total
for i in range(1000000):
#获取一把锁
lock.acquire()
total-=1
#释放锁
lock.release()
thread1=threading.Thread(target=add)
thread2=threading.Thread(target=desc)
thread1.start()
thread2.start()
'''
线程同步机制:
1.
'''
# def add1(a):
# a+=1
# def desc1(a):
# a-=1
# import dis
# print(dis.dis(add1))
# print(dis.dis(desc1))
'''
add
1.load a a=0
2.load 1 1
3.+ 1
4.赋值给a 1
desc
1.load a a=0
2.load 1
3.- -1
4.赋值给a -1
在这个字节码过程当中的任意一个过程,
线程都有可能被切换出去给另一个线程.
使用了锁之后,多线程之间谁先获取锁,那么这个线程就
会先执行自己的代码,并且如果这个线程的锁如果没有在
执行后得到释放,那么所有其他所有线程都会被卡住。
1.使用了锁之后会影响我们的性能,获取锁和释放锁都需
要时间。 这是锁会影响并发性能的必然问题。
2.用锁会引起死锁。非常容易引起死锁。(小心)
死锁的情况:A(a,b)
A(a,b)
首先 acquire (a)
acquire (b)
B(a,b)
acquire (b)
acquire(a)
这种情况下造成锁资源的竞争。
当A线程在和B先程
'''
thread1.join()
thread2.join()
print(total)
#RLock在同一个线程里面,可以连续调用多次acquire,
#一定要注意acquire的次数要和release的次数相等
Condition :
在使用从第同之前先使用lock实验下面的场景,达不到说一句回答一句的
聊天效果。实例代码如下:
from threading import Condition
#Condition条件变量,用于复杂的线程间同步的锁。
from threading import Lock
import threading
class XiaoAi(threading.Thread):
def __init__(self,lock):
self.lock=lock
super().__init__(name="小爱")
def run(self):
self.lock.acquire()
print("{}: 在".format(self.name))
self.lock.release()
self.lock.acquire()
print("{}: 好啊。".format(self.name))
self.lock.release()
pass
class TianMaoJingLing(threading.Thread):
def __init__(self,lock):
self.lock=lock
super().__init__(name="天猫精灵")
def run(self):
self.lock.acquire()
print("{}: 小爱同学".format(self.name))
self.lock.release()
self.lock.acquire()
print("{}: 我们来对古诗吧".format(self.name))
self.lock.release()
if __name__=="__main__":
lock=Lock()
xiaoai=XiaoAi(lock)
tianmao=TianMaoJingLing(lock)
tianmao.start()
xiaoai.start()
使用Condition来实现聊天场景
from threading import Condition
#Condition条件变量,用于复杂的线程间同步的锁。
from threading import Lock
import threading
# class XiaoAi(threading.Thread):
# def __init__(self,lock):
# self.lock=lock
#
# super().__init__(name="小爱")
# def run(self):
# self.lock.acquire()
# print("{}: 在".format(self.name))
# self.lock.release()
# self.lock.acquire()
# print("{}: 好啊。".format(self.name))
# self.lock.release()
# pass
# class TianMaoJingLing(threading.Thread):
# def __init__(self,lock):
# self.lock=lock
# super().__init__(name="天猫精灵")
# def run(self):
# self.lock.acquire()
# print("{}: 小爱同学".format(self.name))
# self.lock.release()
# self.lock.acquire()
# print("{}: 我们来对古诗吧".format(self.name))
# self.lock.release()
# if __name__=="__main__":
# lock=Lock()
# xiaoai=XiaoAi(lock)
# tianmao=TianMaoJingLing(lock)
# tianmao.start()
# xiaoai.start()
from threading import Condition
#通过condition完成协同对话
class XiaoAi(threading.Thread):
def __init__(self,cond):
self.cond=cond
super().__init__(name="小爱")
def run(self):
# with self.cond:
self.cond.acquire()
#等待通知
self.cond.wait()
print("{}: 在".format(self.name))
#通知天猫精灵
self.cond.notify()
#等待通知
self.cond.wait()
print("{}: 好啊.".format(self.name))
#通知天猫精灵
self.cond.notify()
#等待通知
self.cond.wait()
print("{}: 君住长江尾.".format(self.name))
#通知天猫精灵
self.cond.notify()
#等待通知
self.cond.wait()
print("{}: 共饮长江水.".format(self.name))
#通知天猫精灵
self.cond.notify()
#等待通知
self.cond.wait()
print("{}: 此恨何时已.".format(self.name))
#通知天猫精灵
self.cond.notify()
#等待通知
self.cond.wait()
print("{}: 定不负相思忆.".format(self.name))
#通知天猫精灵
self.cond.notify()
self.cond.release()
class TianMaoJingLing(threading.Thread):
def __init__(self,cond):
self.cond=cond
super().__init__(name="天猫精灵")
def run(self):
with self.cond:
print("{}: 小爱同学。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
print("{}: 我们来对古诗吧。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
print("{}: 我在长江头。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
print("{}: 日日思君不见君。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
print("{}: 此水几时休。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
print("{}: 只愿君心似我心。".format(self.name))
#通知小爱同学
self.cond.notify()
#进入等待的状态 等待小爱的通知
self.cond.wait()
if __name__=="__main__":
cond=Condition()
xiaoai=XiaoAi(cond)
tianmao=TianMaoJingLing(cond)
#启动顺序很重要
#在调用with cond 之后才能调用 wait()或者notify()
#condition有两层锁一把底层锁会在线程调用了wait方法
# 的时候释放掉,上面的锁会在每次调用wait的时候分配
#一把锁并放到cond的等待队列中,等待notify方法的唤醒
xiaoai.start()
tianmao.start()
运行结果如下图:
wait()函数允许我们等待某个条件变量的通知
semaphore 是用于控制进入数量的锁
#semphore 是用于控制进入数量的锁
#文件, 读,写,写一般只是用于一个线程写,读可以允许有多个线程读
#爬虫
import threading
import time
class HtmlSpider(threading.Thread):
def __init__(self,url,sem):
super().__init__()
self.url=url
self.sem=sem
def run(self):
time.sleep(2)
print("got html text success")
self.sem.release()
class UrlProducer(threading.Thread):
def __init__(self,sem):
super().__init__(name="")
self.sem=sem
def run(self):
for i in range(20):
self.sem.acquire()
html_thread=HtmlSpider("http://www.baidu.com/{}".format(i),self.sem)
html_thread.start()
if __name__=="__main__":
#控制进入某段代码的线程数量 即每次建立3个线程
sem=threading.Semaphore(3)
url_producer=UrlProducer(sem)
url_producer.start()
'''
输出结果每次输出三个结果。
'''
from queue import Queue
concurrent线程池编程
python3.2+
from concurrent import futures
#线程池 为什么要线程池
'''
能不能有个线程管理包去管理我们的线程,
第一控制线程进入的数量
在主线程中可以获取某某一个线程的状态或者说某一个任务
的状态以及返回值
当一个线程完成的时候我们主线程能够立即知道
futures可以让多线程和多进程编码接口一致
'''
from concurrent.futures import ThreadPoolExecutor,as_completed,wait,FIRST_COMPLETED
#wait可以让我们的主线程阻塞
import time
def get_html(times):
time.sleep(times)
print("get page {} success".format(times))
return times
#实例化线程池
executor=ThreadPoolExecutor(max_workers=2)
#通过submit函数提交执行的函数到线程池中 submit是立即返回是非阻塞的
# task1=executor.submit(get_html,(3))
# task2=executor.submit(get_html,2)
'''
在实际的爬虫当中,我们并不是获取所有的线程的状态,
而是要获取已经成功的task的返回
'''
urls=[3,2,4]
#1批量提交
all_task=[executor.submit(get_html,(url)) for url in urls]
# wait(all_task)
#这样的话,我们就可以控制主线程等待某件事情的发生之后再继续执行
wait(all_task,return_when=FIRST_COMPLETED)
print("main")
#通过as_completed获取成已完成的task的结果1
# for future in as_completed(all_task):
# data=future.result()
# print("get {} page success".format(data))
#2通过executor的map获取已经完成的task的结果
# for result in executor.map(get_html,urls):
# print("get {} page".format(result))
# #done()用于判定某个任务是否完成
# print(task1.done())
# #取消某一个线程
# print(task2.cancel())
# time.sleep(5)
# #是一个阻塞的方法,它能够返回一个结果
# print(task1.done())
# #result可以获取task的执行结果
# print(task1.result())
from concurrent.futures import Future
‘’’
Future == task的返回容器或者未来对象 这一设计理念比较重要
是因为在submit()返回的对象线程任务所处的
状态有可能是未完成的,但是有可能在将来某个时候完成
所以说他是我们异步的核心。
多进程
因为有一把gil锁的存在,python中的多线程实际上无法利用我们多核的优势,无法达到并行的优势,多进程编程就可以利用我们多个cpu并发的这么个需求去提高我们的运行效率。
多进程 与 多线程:
1.对于耗cpu的操作,使用多进程.
2.对于io的操作,使用多线程.切换进程的代价要高于线程
对于耗费cpu的操作,计算,图形处理,机器学习的算法,以及流行的比特币挖矿等等耗费到cpu已经不能够满足计算的需求,所以说现在的显卡里面的GPU它的运算速度是高于CPU的 。 对于耗费cpu的操作,多进程优于多线程。
#多cpu的操作用多进程编程
#1.对于耗cpu的操作,使用多进程。
# 2.对于io的操作,使用多线程.切换进程的代价要高于线程。
'''
多进程和多线程使用concurrent.futures的效率是差不多的。
'''
def fibo(n):
if n<2:
return 1
return fibo(n-1)+fibo(n-2)
# print(fibo(10))#89
# 1.使用多线程
from concurrent.futures import ThreadPoolExecutor,as_completed
import time
# with ThreadPoolExecutor(3) as excutor:
# alltask=[excutor.submit(fibo,(num)) for num in range(25,35)]
# starttime=time.time()
# for future in as_completed(alltask):
# data=future.result()
# print("get numbers results is: {}".format(data))
# print("last time is:{}".format(time.time()-starttime))
'''
89
get numbers results is: 121393
get numbers results is: 196418
get numbers results is: 317811
get numbers results is: 514229
get numbers results is: 832040
get numbers results is: 1346269
get numbers results is: 2178309
get numbers results is: 3524578
get numbers results is: 5702887
get numbers results is: 9227465
last time is:15.730899810791016
'''
#2.多进程
import time
from concurrent.futures import ProcessPoolExecutor
'''
注意:windows多进程编程时一定要将执行的ProcessPoolExecutor代码放到
if __name__=="__main__":之下,不然会报错。
'''
if __name__=="__main__":
with ProcessPoolExecutor(3) as excutor:
alltask = [excutor.submit(fibo, (num)) for num in range(25, 45)]
starttime = time.time()
for future in as_completed(alltask):
data = future.result()
print("get numbers results is: {}".format(data))
print("last time is:{}".format(time.time() - starttime))
'''
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter11/progress_test.py
get numbers results is: 121393
get numbers results is: 196418
get numbers results is: 317811
get numbers results is: 514229
get numbers results is: 832040
get numbers results is: 1346269
get numbers results is: 2178309
get numbers results is: 3524578
get numbers results is: 5702887
get numbers results is: 9227465
last time is:9.456540822982788
'''
对于io操作来说,多线程优于我们的多进程:
#对于io操作来说,多线程优于我们的多进程
def random_sleep(n):
time.sleep(n)
return n
# if __name__=="__main__":
# with ThreadPoolExecutor(3) as excutor:
# alltask = [excutor.submit(random_sleep, (num)) for num in [2]*30]
# starttime = time.time()
# for future in as_completed(alltask):
# data = future.result()
# print("get numbers results is: {}".format(data))
# print("last time is:{}".format(time.time() - starttime))
'''
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter11/progress_test.py
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
last time is:20.00114417076111
'''
if __name__=="__main__":
with ProcessPoolExecutor(3) as excutor:
alltask = [excutor.submit(random_sleep, (num)) for num in [2]*30]
starttime = time.time()
for future in as_completed(alltask):
data = future.result()
print("get numbers results is: {}".format(data))
print("last time is:{}".format(time.time() - starttime))
'''
H:\ANACONDA\python.exe I:/ainlp/pythonHight/chapter11/progress_test.py
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
get numbers results is: 2
last time is:20.690183401107788
'''
其实在计算量不是很大的时候,多线程和多进程性能差别不大。操作系统调用的线程数比进程数要多很多,调用和切换进程会消耗很多的cpu内存,因此在某些情况下使用多线程的性能是不会比多进程差的,而且多线程的稳定性是比多进程好的。
多进程编程:
先看一下这个东西:
import os
import time
#fork只能用于linux/unix上
pid =os.fork()
print("xiaopang")
if pid==0:
print('子进程 {} ,父进程是: {}.'.format(os.getpid(),os.getppid()))
else:
print('我是父进程 : {}'.format(pid))
time.sleep(2)
运行结果:
为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
将print("xiaopang ")放在fok()的前面。
import os
import time
#fork只能用于linux/unix上
print("xiaopang")
pid =os.fork()
if pid==0:
print('子进程 {} ,父进程是: {}.'.format(os.getpid(),os.getppid()))
else:
print('我是父进程 : {}'.format(pid))
time.sleep(2)
多进程和进程池
from concurrent.futures import ProcessPoolExecutor
import multiprocessing
#多进程编程
import time
def get_html(n):
time.sleep(n)
print("sub_progress success")
return n
if __name__=="__main__":
# process=multiprocessing.Process(target=get_html,args=(2,))
# print(process.pid)
# process.start()
# print(process.pid)
# process.join()
# print("main progress end")
# #使用进程池
pool=multiprocessing.Pool(multiprocessing.cpu_count())
# result=pool.apply_async(get_html,args=(3,))
# #等待所有任务完成
# pool.close()
# pool.join()
# print(result.get())
#imap
# for result in pool.imap(get_html,[1,5,3]):
# print("{} sleep success".format(result))
#imap_unordered
for result in pool.imap_unordered(get_html,[1,5,3]):
print("{} sleep success".format(result))
多进程之间的通信
1使用multiprogressing 中的queue在进程之间进行通信
from multiprocessing import Process,Queue
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def cusumer(queue):
time.sleep(2)
data=queue.get()
print(data)
if __name__=="__main__":
queue=Queue(10)
myproducer=Process(target=producer,args=(queue,))
mycusumer=Process(target=cusumer,args=(queue,))
myproducer.start()
mycusumer.start()
myproducer.join()
mycusumer.join()
multiprocessing中的queue不能用于进程池的通讯,因为
不起作用。
#multiprocessing中的queue不能用于进程池的通讯
from multiprocessing import Process,Queue,Pool
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def cusumer(queue):
time.sleep(2)
data=queue.get()
print(data)
if __name__=="__main__":
queue=Queue(10)
pool=Pool(2)
pool.apply_async(producer,args=(queue,))
pool.apply_async(cusumer,args=(queue,))
pool.close()
pool.join()
可以使用Manage之下的queue进行进程池间的通信
from multiprocessing import Process,Queue,Pool,Manager
import time
def producer(queue):
queue.put("a")
time.sleep(2)
def cusumer(queue):
time.sleep(2)
data=queue.get()
print(data)
if __name__=="__main__":
queue=Manager().Queue(10)
pool=Pool(2)
pool.apply_async(producer,args=(queue,))
pool.apply_async(cusumer,args=(queue,))
pool.close()
pool.join()
进程间通讯的方式 管道pipe
pipe的性能高于queue
pipe只能用于两个进程间的通讯
#进程间通讯的方式 管道pipe
# pipe的性能高于queue
# pipe只能用于两个进程间的通讯
from multiprocessing import Process,Pipe
#Pipe是简化版的queue
import time
def producer(pipe):
pipe.send("xiaopang")
def cusumer(pipe):
print(pipe.recv())
if __name__=="__main__":
recevie_pipe,send_pipe=Pipe()
# pipe只能用于两个进程间的通讯
myproducer=Process(target=producer,args=(send_pipe,))
mycusumer=Process(target=cusumer,args=(recevie_pipe,))
myproducer.start()
mycusumer.start()
myproducer.join()
mycusumer.join()
使用Manage里的dict进行进程间的共享内存操作,注意数据间的进程同步.
# 使用Manage里的dict进行进程间的共享内存操作
from multiprocessing import Manager,Process
def add_data(p_dict,key,value):
p_dict[key]=value
if __name__=="__main__":
process_dict=Manager().dict()
first_Process=Process(target=add_data,args=(process_dict,"xiaopang ",23))
second_process=Process(target=add_data,args=(process_dict,"xiaohe",26))
first_Process.start()
second_process.start()
first_Process.join()
second_process.join()
print(process_dict)
完结
下一篇: 协程和异步io