网站外链快速建设,粤康码小程序,建设彩票网站需要哪些要求,国外seo查询1、Python对并发编程的支持
多线程: threading, 利用CPU和IO可以同时执行的原理,让CPU不会干巴巴等待IO完成多进程: multiprocessing, 利用多核CPU的能力#xff0c;真正的并行执行任务异步IO: asyncio,在单线程利用CPU和IO同时执行的原理#xff0c;实现函数异步执行使用Lo…1、Python对并发编程的支持
多线程: threading, 利用CPU和IO可以同时执行的原理,让CPU不会干巴巴等待IO完成多进程: multiprocessing, 利用多核CPU的能力真正的并行执行任务异步IO: asyncio,在单线程利用CPU和IO同时执行的原理实现函数异步执行使用Lock对资源加锁防止冲突访问使用Queue实现不同线程/进程之间的数据通信实现生产者-消费者模式使用线程池Pool/进程池Pool,简化线程/进程的任务提交、等待结束、获取结果使用subprocess启动外部程序的进程并进行输入输出交互
2、 怎样选择多线程多进程多协程
Python并发编程有3三种方式多线程Thread、多进程Process、多协程Coroutine
2.1 什么是CPU密集型计算、IO密集型计算?
CPU密集型CPU-bound ) : CPU密集型也叫计算密集型是指I/O在很短的时间就可以完成CPU需要大量的计算和处理特点是CPU占用率相当高 例如压缩解压缩、加密解密、正则表达式搜索 IO密集型I/0 bound: IO密集型指的是系统运作大部分的状况是CPU在等I/O (硬盘/内存)的读/写操作CPU占用率仍然较低。 例如文件处理程序、网络爬虫程序、读写数据库程序依赖大量的外部资源
2.2 多线程、多进程、多协程的对比
一个进程中可以启动N个线程一个线程中可以启动N个协程 多进程Process ( multiprocessing )
优点可以利用多核CPU并行运算缺点占用资源最多、可启动数目比线程少适用于CPU密集型计算
多线程Thread ( threading)
优点相比进程更轻量级、占用资源少缺点 相比进程:多线程只能并发执行不能利用多CPU ( GIL ) 相比协程启动数目有限制占用内存资源有线程切换开销适用于 IO密集型计算、同时运行的任务数目要求不多
多协程Coroutine ( asyncio )
优点内存开销最少、启动协程数量最多缺点支持的库有限制aiohttp VS requests )、代码实现复杂适用于IO密集型计算、需要超多任务运行、但有现成库支持的场景
2.3 怎样根据任务选择对应技术? #mermaid-svg-2tAAP7txFWx9Nb6o {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .error-icon{fill:#552222;}#mermaid-svg-2tAAP7txFWx9Nb6o .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2tAAP7txFWx9Nb6o .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-2tAAP7txFWx9Nb6o .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2tAAP7txFWx9Nb6o .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2tAAP7txFWx9Nb6o .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2tAAP7txFWx9Nb6o .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2tAAP7txFWx9Nb6o .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2tAAP7txFWx9Nb6o .marker.cross{stroke:#333333;}#mermaid-svg-2tAAP7txFWx9Nb6o svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2tAAP7txFWx9Nb6o .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .cluster-label text{fill:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .cluster-label span{color:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .label text,#mermaid-svg-2tAAP7txFWx9Nb6o span{fill:#333;color:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .node rect,#mermaid-svg-2tAAP7txFWx9Nb6o .node circle,#mermaid-svg-2tAAP7txFWx9Nb6o .node ellipse,#mermaid-svg-2tAAP7txFWx9Nb6o .node polygon,#mermaid-svg-2tAAP7txFWx9Nb6o .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2tAAP7txFWx9Nb6o .node .label{text-align:center;}#mermaid-svg-2tAAP7txFWx9Nb6o .node.clickable{cursor:pointer;}#mermaid-svg-2tAAP7txFWx9Nb6o .arrowheadPath{fill:#333333;}#mermaid-svg-2tAAP7txFWx9Nb6o .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2tAAP7txFWx9Nb6o .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2tAAP7txFWx9Nb6o .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-2tAAP7txFWx9Nb6o .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-2tAAP7txFWx9Nb6o .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2tAAP7txFWx9Nb6o .cluster text{fill:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o .cluster span{color:#333;}#mermaid-svg-2tAAP7txFWx9Nb6o div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2tAAP7txFWx9Nb6o :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否 是 待执行任务 任务特点 CPU密集型 使用多进程 multiprocessing IO密集型 1、需要超多任务量 2、有现成协程库支持 3、协程实现复杂度可接受 使用多线程 threading 使用多协程 asyncio flowchart LRA[待执行任务]--B{任务特点}B --- C(CPU密集型)
C--E([使用多进程multiprocessing])B ---D(IO密集型)D--F{1、需要超多任务量2、有现成协程库支持3、协程实现复杂度可接受}
F -- 否--- G([使用多线程threading])
F -- 是--- H([使用多协程asyncio])%% style选项为每个节点设置了颜色和边框样式
style A fill:#333399,color:#fff
style B fill:#fff,stroke:#CC6600
style C fill:#FFFFCC
style D fill:#FFFFCC
style E fill:#FF9999
style F fill:#fff,stroke:#CC6600
style G fill:#FF9999
style H fill:#FF9999%% linkStyle选项为连接线设置颜色和样式
linkStyle 1 stroke:blue,stroke-width:1px;
linkStyle 3 stroke:blue,stroke-width:1px;3、 Python速度慢的罪魁祸首——全局解释器锁GIL
3.1 Python速度慢的两大原因
相比C/C /JAVA, Python确实慢在一些特殊场景 下Python比C 慢100~ 200倍 由于速度慢的原因很多公司的基础架构代码依然用C/C 开发 比如各大公司阿里/腾讯/快手的推荐引擎、搜索引擎、存储引擎等底层对性能要求高的模块 Python速度慢的原因1 动态类型语言边解释边执行 Python速度慢的原因2 GIL 无法利用多核CP并发执行
3.2 GIL是什么?
全局解释器锁( 英语: Global Interpreter Lock,缩写GIL) 是计算机程序设计语言解释器用于同步线程的一种机制它使得任何时刻仅有一个线程在执行。 即便在多核心处理器上使用GIL的解释器也只允许同一时间执行一个线程。 由于GIL的存在即使电脑有多核CPU单个时刻也只能使用1个相比并发加速的C /JAVA所以慢
3.3 为什么有GIL .这个东西?
简而言之: Python设计初期为了规避并发问题引入了GIL,现在想去除却去不掉了! 为了解决多线程之间数据完整性和状态同步问题 Python中对象的管理是使用引用计数器进行的引用数为0则释放对象 开始:线程A和线程B都引用了对象objobj.ref_ num 2,线程A和B都想撤销对obj的引用 GIL确实有好处简化了Python对共享资源的管理;
3.4 怎样规避GIL带来的限制?
多线程threading机制依然是有用的用于IO密集型计算 因为在I/O (read,write ,send,recv,etc. )期间线程会释放GIL实现CPU和IO的并行 因此多线程用于IO密集型计算依然可以大幅提升速度 但是多线程用于CPU密集型计算时只会更加拖慢速度 使用multiprocessing的多进程机制实现并行计算、利用多核CPU优势 为了应对GIL的问题Python提供了multiprocessing
4、使用多线程爬虫被加速
4.1 Python创建多线程的方法
1、准备一个函数
def my_func(a,b):do_craw(a,b)2、创建一个线程
import threading
t threading.Thread(targetmy_func,args(100,200))3、启动线程
t.start()4、等待结束
t.join()4.2 改写爬虫程序变成多线程爬取
blog_spider.py程序
import requestsurls [fhttps://www.cnblogs.com/sitehome/p/{page}for page in range(1, 50 1)
]def craw(url):r requests.get(url)print(url, len(r.text))import blog_spider
import threading
import timedef single_thread():print(single_thread begin...)for url in blog_spider.urls:blog_spider.craw(url)print(single_thread end...)def multi_thread():print(multi_thread begin...)threads []for url in blog_spider.urls:threads.append(threading.Thread(targetblog_spider.craw,args(url,)))for thread in threads:thread.start()for thread in threads:thread.join()print(multi_thread end...)if __name__ __main__:start time.time()single_thread()endtime.time()print(single thread cost:,end-start,seconds)begin time.time()multi_thread()finish time.time()print(multi thread cost:, finish - begin, seconds)4.3 速度对比:单线程爬虫VS多线程爬虫 5 Python实现生产者消费者爬虫
5.1 多组件的Pipeline技术架构
复杂的事情一般都不会一下子做完 而是会分很多中间步骤一步步完成。 #mermaid-svg-EYBlGXksSKKz9BnH {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .error-icon{fill:#552222;}#mermaid-svg-EYBlGXksSKKz9BnH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EYBlGXksSKKz9BnH .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-EYBlGXksSKKz9BnH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EYBlGXksSKKz9BnH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EYBlGXksSKKz9BnH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EYBlGXksSKKz9BnH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EYBlGXksSKKz9BnH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EYBlGXksSKKz9BnH .marker.cross{stroke:#333333;}#mermaid-svg-EYBlGXksSKKz9BnH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EYBlGXksSKKz9BnH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .cluster-label text{fill:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .cluster-label span{color:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .label text,#mermaid-svg-EYBlGXksSKKz9BnH span{fill:#333;color:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .node rect,#mermaid-svg-EYBlGXksSKKz9BnH .node circle,#mermaid-svg-EYBlGXksSKKz9BnH .node ellipse,#mermaid-svg-EYBlGXksSKKz9BnH .node polygon,#mermaid-svg-EYBlGXksSKKz9BnH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EYBlGXksSKKz9BnH .node .label{text-align:center;}#mermaid-svg-EYBlGXksSKKz9BnH .node.clickable{cursor:pointer;}#mermaid-svg-EYBlGXksSKKz9BnH .arrowheadPath{fill:#333333;}#mermaid-svg-EYBlGXksSKKz9BnH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EYBlGXksSKKz9BnH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EYBlGXksSKKz9BnH .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-EYBlGXksSKKz9BnH .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-EYBlGXksSKKz9BnH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EYBlGXksSKKz9BnH .cluster text{fill:#333;}#mermaid-svg-EYBlGXksSKKz9BnH .cluster span{color:#333;}#mermaid-svg-EYBlGXksSKKz9BnH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EYBlGXksSKKz9BnH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 消费者 生产者 输入数据 中间数据 中间数据 输出数据 处理器N 处理器1 处理器X 很多个 graph LR
O[ ] -- |输入数据|A(处理器1)--|中间数据|B(处理器Xbr很多个)--|中间数据|C(处理器N)--|输出数据|D[ ]5.2 生产者消费者爬虫的架构
5.3 多线程数据通信的queue.Queue
5.4 代码编写实现生产者消费者爬虫
import requests
from bs4 import BeautifulSoupurls [# fhttps://www.cnblogs.com/#p{page}fhttps://www.cnblogs.com/sitehome/p/{page}for page in range(1, 3 1)
]def craw(url):r requests.get(url)return r.textdef parse(html):soupBeautifulSoup(html,html.parser)links soup.find_all(a,class_post-item-title)return [(link[href],link.get_text()) for link in links]if __name__ __main__:for result in parse(craw(urls[0])):print(result)import blog_spider
import threading
import time
import queue
import randomdef do_craw(url_queue: queue.Queue, html_queue: queue.Queue):while True:url url_queue.get()html blog_spider.craw(url)html_queue.put(html)print(threading.current_thread().name, fcraw {url},url_queue.size, url_queue.qsize())# time.sleep(random.randint(1, 2))def do_parse(html_queue: queue.Queue, fout):while True:html html_queue.get()results blog_spider.parse(html)for result in results:fout.write(str(result) \n)print(threading.current_thread().name, fresults.size {len(results)},html_queue.size, html_queue.qsize())# time.sleep(random.randint(1, 2))if __name__ __main__:url_queue queue.Queue()html_queue queue.Queue()for url in blog_spider.urls:url_queue.put(url)for idx in range(3):t threading.Thread(targetdo_craw, args(url_queue, html_queue), namefcraw{idx})t.start()fout open(02.data.txt, w, encodingutf-8)for idx in range(2):t threading.Thread(targetdo_parse, args(html_queue, fout), namefparse{idx})t.start()6、Python线程安全问题以及解决方案
import threading
import timelock threading.Lock()class Accout():def __init__(self,balance):self.balancebalancedef draw(accout,amount):with lock:if accout.balanceamount:time.sleep(0.1)print(threading.current_thread().name,取钱成功)accout.balance-amountprint(threading.current_thread().name, 余额,accout.balance)else:print(threading.current_thread().name, 取钱失败余额不足)if __name__ __main__:accoutAccout(1000)ta threading.Thread(targetdraw,args(accout,600))tb threading.Thread(targetdraw, args(accout, 600))ta.start()tb.start()ta.join()tb.join()7、Python好用的线程池ThreadPoolExecutor
import concurrent.futures
import blog_spiderwith concurrent.futures.ThreadPoolExecutor() as pool:htmls pool.map(blog_spider.craw, blog_spider.urls)htmls list(zip(blog_spider.urls, htmls))for url, html in htmls:print(url, len(html))print(爬虫结束..)with concurrent.futures.ThreadPoolExecutor() as pool:futures {}for url, html in htmls:future pool.submit(blog_spider.parse, html)futures[future] url# for future,url in futures.items():# print(url,future.result())for future in concurrent.futures.as_completed(futures):# url futures[future]futures[future] urlprint(url, future.result())8、Python使用线程池在Web服务中实现加速
import flask
import json
import time
from concurrent.futures import ThreadPoolExecutor
app flask.Flask(__name__)
pool ThreadPoolExecutor()def read_db():time.sleep(0.2)return db resultdef read_file():time.sleep(0.1)return file resultdef read_api():time.sleep(0.3)return api resultapp.route(/)
def index():result_filepool.submit(read_file)result_db pool.submit(read_db)result_api pool.submit(read_api)return json.dumps({result_file:result_file.result(),result_db: result_db.result(),result_db: result_api.result(),})if __name__ __main__:app.run()9、使用多进程multiprocessing模块加速程序的运行
import math
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import timePRIMES [112272535095293] * 10def is_prime(n):if n 2:return Falseif n 2:return Trueif n % 2 0:return Falsesqrt_n int(math.floor(math.sqrt(n)))for i in range(3, sqrt_n 1, 2):if n % i 0:return Falsereturn Truedef single_thread():for num in PRIMES:is_prime(num)def multi_thread():with ThreadPoolExecutor() as pool:pool.map(is_prime, PRIMES)def multi_process():with ProcessPoolExecutor() as pool:pool.map(is_prime, PRIMES)if __name__ __main__:start time.time()single_thread()end time.time()print(single thread cost:, end - start, secend)start time.time()multi_thread()end time.time()print(multi thread cost:, end - start, secend)start time.time()multi_process()end time.time()print(multi process cost:, end - start, secend) 10、Python在Flask服务中使用多进程池加速程序运行
import flask
import math
import json
from concurrent.futures import ProcessPoolExecutorapp flask.Flask(__name__)def is_prime(n):if n 2:return Falseif n 2:return Trueif n % 2 0:return Falsesqrt_n int(math.floor(math.sqrt(n)))for i in range(3, sqrt_n 1, 2):if n % i 0:return Falsereturn Trueapp.route(/is_prime/numbers)
def api_is_prime(numbers):number_list [int(x) for x in numbers.split(,)]results process_pool.map(is_prime, number_list)return json.dumps(dict(zip(number_list, results)))if __name__ __main__:process_pool ProcessPoolExecutor()app.run()
11、Python异步IO实现并发爬虫
import asyncio
import aiohttp
import blog_spider
import timeasync def async_craw(url):print(爬虫开始, url)async with aiohttp.ClientSession() as session:async with session.get(url) as resp:result await resp.text()print(fcraw url:{url},{len(result)})loop asyncio.get_event_loop()tasks [loop.create_task(async_craw(url)) for url in blog_spider.urls]start time.time()
loop.run_until_complete(asyncio.wait(tasks))
end time.time()
print(asyncio cost:, end - start, second)12、在异步IO中使用信号量控制爬虫并发度
import asyncio
import aiohttp
import blog_spider
import timeasync def async_craw(url):print(爬虫开始, url)async with aiohttp.ClientSession() as session:async with session.get(url) as resp:result await resp.text()print(fcraw url:{url},{len(result)})loop asyncio.get_event_loop()tasks [loop.create_task(async_craw(url)) for url in blog_spider.urls]start time.time()
loop.run_until_complete(asyncio.wait(tasks))
end time.time()
print(asyncio cost:, end - start, second)参考【2021最新版】Python 并发编程实战用多线程、多进程、多协程加速程序运行