python多任务编程
使用Lock对资源加锁,防止冲突访问
 使用Queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式
 使用线程池Pool/进程池Pool,简化线程/进程的任务提交、等待结束、获取结果
 使用subprocess启动外部程序的进程,并进行输入输出交互
python并发编程
- 多线程
- 多进程
- 多协程
CPU密集型计算/IO密集型计算
- **cpu密集型计算:**也叫计算密集型,是指I/O在很短的时间就可以完成,CPU需要大量的计算和处理,特点是CPU占用率非常高
 例如:压缩解压缩、加密解密、正则表达式搜索
- IO密集型:系统运作大部分的状况是CPU在等I/O的读/写操作,CPU占用率仍然较低
 例如:文件处理程序、网络爬虫程序、读写数据库程序
多线程、多进程、多协程对比
python速度慢的两大原因:
相比于C/C++/JAVA,python确实慢,在一些特殊场景下,python比C++慢100~200倍
 1、动态类型语言 边解释边执行
 2、GIL 无法利用多核CPU并发执行
GIL是什么?
全局解释器锁:是计算机程序设计语言解释器用于同步线程的一种机制,他使得任何时刻仅有一个线程在执行
 即便在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程
为什么有GIL这个东西?
为了解决多线程之间数据完整性和状态同步问题
怎样规避GIL带来的限制?
1、多线程机制仍然是有用的,用于I/O密集型计算
 因为在I/O期间,线程会释放GIL,实现CPU和IO的并行。因此多线程用于IO密集型计算仍可以大幅度提升速度
 但是多线程用于CPU密集型计算时,只会更加拖慢速度
2、使用multiprocessing的多进程制实现并行计算、利用多核CPU优势
 对了应对GIL,python提供提供了multiprocessing
线程安全概念介绍
线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能能正确完成
 由于线程的执行随时会发生切换,就造成了不可预料的结果,出现线程不安全
Lock用于解决线程安全问题
 用法一:try-finally模式: 
 import threading 
 lock = threading.Lock()
 lock.acquire() 
 try:
     # do something 
finally:
      lock.release()
 
用法二:with模式
import threading l
lock = threading.Lock() 
with lock:
      # do something
python好用的线程池ThreadPoolExecutor

使用线程池的好处
1、提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源
 2、使用场景:适合处理突发性大量请求或需要大量线程完成任务、但实际任务处理时间较短
 3、防御功能:能有效避免系统因为创建线程过多,而导致系统负荷过大相应变慢等问题
 4、代码优势:使用线程池的语法比自己新建线程执行线程更加整洁
ThreadPoolExecutor的使用语法
from concurrent.futures import ThreadPoolExecutor,as_completed
# 用法一:map函数很简单,注意map的结果和入参是顺序对应的
with ThreadPoolExecutor() as pool:
     results = pool.map(craw,urls)
     for result in results:
          print(result)
 # 用法二:future模式,更强大  注意如果用as_completed顺序是不定的
with ThreadPoolExecutor as pool:
     futures = [pool.submit(craw,url) for url in urls]  
     for future in futures:
          print(future.result())
     for future in as_completed(futures):
          print(future.result())     
python使用线程在web服务中实现加速
1、web服务的架构以及特点
Web后台服务的特点:
 1、web服务对相应时间要求非常高,不如要求200MS返回
 2、web服务有大量的依赖IO操作的调用,比如磁盘文件、数据库、远程API
2、使用线程池ThreadPoolExecutor加速
使用线程池ThreadPoolExcutor的好处:
 1、方便的将磁盘文件、数据库、远程API的IO调用并发执行
 2、线程池的线程数目不会无线创建(导致系统挂掉),具有防御功能
import flask
import json
import time
from concurrent.futures import ThreadPoolExecutor
app = flask.Flask(__name__)
pool = ThreadPoolExecutor()
def read_file():
    time.sleep(0.1)
    return "file_result"
def read_db():
    time.sleep(0.2)
    return "read db"
def read_api():
    time.sleep(0.3)
    return "read api"
@app_route("/")
def index():
    result_file = pool.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_api": result_api.result()
    })
if __name__ == '__main__':
    app.run()
python进程(适用于CPU密集型)

python协程:在单线程内实现并发
核心原理:用一个超级循环(其实就是while true)循环;配合IO多路复用原理(IO时可以去干其他事情)
python异步IO库:asyncio
import asyncio
# 获取时间循环
loop = asyncio.get_event_loop()
# 定义协程
async def myfunc(url):
     await get_url(url)
# 创建task列表
tasks = [loop.create_task(my_func(url)) for url in urls]
# 执行爬虫时间列表
loop.run_until_complete(asyncio.wait(tasks))
注意:
需要在异步IO变成中
以来的库必须支持异步IO特征
爬虫引用中:requests 不支持异步  需要用aiohttp
在异步IO中使用信号量控制爬虫并发度
import asyncio
import aiohttp
urls = [
    "https://www.cnblogs.com/#p{page}".format(page=page)
    for page in range(1,50+1)
]
# 进行初始化一个并发量
semaphore = asyncio.Semaphore(10)
async def async_craw(url):
    # 设置并发量
    async with semaphore:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as resp:
                result = await resp.text()
                print(f"craw url:{url}".format(url=url),{len(result)})
loop = asyncio.get_event_loop()
# 创建task列表
tasks = [loop.create_task(async_craw(url)) for url in urls]
import time
start = time.time()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("use time second:" ,end - start)










