您的位置:首页 > 编程语言 > Python开发

Python 中的串行执行 并发执行 同步异步

2017-11-10 14:22 519 查看
程序的执行:

串行执行:

import requests
import time

def get_page(url):
print('GET: %s' %url)
response=requests.get(url)
print(url,len(response.text))
return response.text

urls=[
'https://www.baidu.com',
'https://www.python.org',
'https://www.openstack.org'
]

#程序的执行是串行执行
start=time.time()
for url in urls:
res=get_page(url) #任务的调用方式是同步调用:提交一个任务,然后在原地等待,等待返回结果后再执行下一行代码
stop=time.time()
print(stop-start) #2.664152145385742


串行不以为效率一定低,当程序是纯计算的话,串行执行并没有效率问题.

但是如果遇到IO密集型程序串行使,效率极低.

所以需要进行 并发

并发执行(并行执行):

from multiprocessing import Process
from threading import Thread
import requests
import time

def get_page(url):
print('GET: %s' %url)
response=requests.get(url)
print(url,len(response.text))
return response.text

urls=[
'https://www.baidu.com',
'https://www.python.org',
'https://www.openstack.org'
]

if __name__ == '__main__':#在python中开启多进程,需要在__main__下执行

#程序的执行是串行执行
start=time.time()
p_l=[]
for url in urls:
p=Thread(target=get_page,args=(url,))#多线程
p_l.append(p)
# p = Process(target=get_page, args=(url,)) #多进程
# p_l.append(p)
p.start()
for p in p_l:
p.join()
stop=time.time()
print(stop-start) #2.664152145385742


开启多进程或多线程并发执行,彼此互不干扰.

虽然python存在GIL锁,但在IO密集型时,多线程是有用的.

但是我们并不能无限制的开线程或者开进程,所以需要进程池或线程池.

进程池 线程池:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

from multiprocessing import Process
from threading import Thread
import requests
import time

def get_page(url):
print('GET: %s' %url)
response=requests.get(url)
return len(response.text)

urls=[
'https://www.baidu.com',
'https://www.python.org',
'https://www.openstack.org'
]

if __name__ == '__main__':
p=ProcessPoolExecutor(4)#默认是你CPU核心数量

#程序的执行是串行执行
start=time.time()
l=[]
for url in urls:
furture=p.submit(get_page,url) #任务的调用方式是异步调用:提交一个任务,不用等待,直接执行下一行代码
l.append(furture)
p.shutdown(wait=True)
for f in l:
print(f.result())
stop=time.time()
print(stop-start) #2.664152145385742


上边这个代码虽然调用任务是异步调用,但是查看结果时,还是串行查询,降低了效率,所以在异步调用时候要结合回调机制来使用.

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

from multiprocessing import Process
from threading import Thread
import requests
import time,os,random

def get_page(url):
print('%s GET: %s' %(os.getpid(),url))
response=requests.get(url)
# time.sleep(random.randint(1,3))
return len(response.text)

def parse_page(res):

res=res.result()
print('%s parse res: %s' %(os.getpid(),res))

urls=[
'https://www.baidu.com',
'https://www.python.org',
'https://www.openstack.org'
]

if __name__ == '__main__':
p=ProcessPoolExecutor(2)

#程序的执行是串行执行
start=time.time()
for url in urls:
# p.submit(get_page,url).add_done_callback(parse_page)
p.submit(get_page,url)
p.shutdown(wait=True)
stop=time.time()
print(stop-start) #2.664152145385742

print('主',os.getpid())


将进程或线程控制在一定数量内(计算机可以承受的范围内).

但是如果任务规模 数量变大,池是有局限性,从而降低效率.

所以如何解决IO问题才是关键

执行任务的方式有同步和异步两种方式,即同步调用,异步调用.

同步调用:

提交完任务后,在原地等待任务执行完毕,拿到返回值,再执行下一行代码

异步调用 + 回调机制:

提交完任务(捆绑一个回调函数)后,不等待任务的执行,直接执行下一行代码,然后等到进程有结果直接触发回调函数的执行.

阻塞指的是进程的一种状态,在进程遇到IO时,会被操作系统夺走CPU的执行权限.

所以我们需要寻找以各种解决方案:

能检测单线程下的IO

遇到IO自动切换

python3.3之后,新增了asynico模块,可以帮组我们检测IO(只能是网络IO),实现应用程序的切换.

twisted 是一个网络框架,其中一个功能是发送异步请求,检测IO并自动切换.

tornado 框架,也能实现该功能.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: