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

来源:互联网 发布:node 构建项目 编辑:程序博客网 时间:2024/06/05 04:28

程序的执行:
串行执行:

import requestsimport timedef get_page(url):    print('GET: %s' %url)    response=requests.get(url)    print(url,len(response.text))    return response.texturls=[    '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 Processfrom threading import Threadimport requestsimport timedef get_page(url):    print('GET: %s' %url)    response=requests.get(url)    print(url,len(response.text))    return response.texturls=[    '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,ProcessPoolExecutorfrom multiprocessing import Processfrom threading import Threadimport requestsimport timedef 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,ProcessPoolExecutorfrom multiprocessing import Processfrom threading import Threadimport requestsimport time,os,randomdef 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 框架,也能实现该功能.

阅读全文
0 0
原创粉丝点击