概念
进程:进程是一种抽象概念。是计算机资源分配的最小单元。由程序,数据集合和进程控制块(PCB,保存进程的描述和控制信息,也是进程存在的标识)。白话叫执行一个程序系统就开辟一个独立的内存块。系统分配资源按照进程为单位。
线程:轻量级进程,是系统调度最小单位。因为进程切换开销很大,发明了线程。一个进程有一个或者多个线程
协程:基于线程之上,更轻量级的存在,由程序员自己调度的用户线程。发生在用户态对内核不可见。减少上下文切换提高效率。
GIL:全局解释器锁。为了数据安全(指进程的数据安全,防止多线程执行过程中对进程数据和指令的破坏)每个cpu(超线程,一物理cpu能分成俩虚拟的)只能执行一个线程。只有获取到GIL锁的线程才能执行。python2里通过一个计数器ticks到100了就切换。(所以多线程关于cpu计算密集型任务不友好,一个线程一直在计算也没办法切换,那用多线程干啥呢)python3中换成了时间计数器,过一段时间就换。
python中的多进程代码
import os, time
from multiprocessing import Process, Queue, Pool, Manager
def run_pro(name:str, q:Queue):
pid = os.getpid()
q.put(pid)
print("running process %s", name)
time.sleep(3)
print("done with %s", name)
def main():
// 注释部分为调用Process进行多进程
# q = Queue()
q = Manager().Queue() // 利用进程池时,要用这个Q
# p1 = Process(target=run_pro, args=("p1", q))
# p2 = Process(target=run_pro, args=("p2", q))
# p1.start()
# p2.start()
# print(q.get(timeout=120, block=True)) // 超时时间和是否阻塞
# print(q.get(timeout=120, block=True))
# p1.join() // 子进程加入到主进程,即主进程执行完等子进程
# p2.join()
pool = Pool(4) // 若进程只有4个任务有10个,则要等进程执行完
for i in range(10):
pool.apply_async(run_pro, args=(str(i), q)) // aplly 是同步执行
pool.close()
pool.join()
if __name__ == '__main__':
main()
多线程的基本调用和多进程基本类似,并提供互斥锁等保护线程安全
进程之间的通信
代码中用到了q,python中还可以用pipe。在Linux中进程通信方式有:信号,信号量,socket(套接字,域名协议端口),共享内存,数据库,管道等python中都有响应的模块实现
协程
Python对协程的支持是通过generator实现的。函数中有关键字yeild称为生成器,generator。
1 import random
2
3
4 def cuns():
5 n = 10
6 while True:
7 print("n", n)
8 n = yield random.randrange(0, n)
9
10
11def pro(c):
12 print("start")
13 c.send(None)
14 print("start send")
15 req = c.send(4)
16 print("req", req)
17 c.close()
if __name__ == '__main__':
c = cuns()
pro(c)
-
通过调用next()或者send()方法调用生成器
-
每调用一次代码走到下一个yield之前,故第一次调用不返回,并且send方法第一次调用参数是None
-
send的参数即是yeild的前边的变量,代码8行
-
正常的生成器走完抛出StopIteration错误,也可使用close方法关闭
异步
异步是利用了协程的原理(下文代买来自网络)
import requests, time, asyncio
async def test2(i):
r = await other_test(i)
print(i,r)
async def other_test(i):
r = requests.get(i)
print(i)
await asyncio.sleep(4)
print(time.time()-start)
return r
url = ["https://segmentfault.com/p/1210000013564725",
"https://www.jianshu.com/p/83badc8028bd",
"https://www.baidu.com/"]
loop = asyncio.get_event_loop()
task = [asyncio.ensure_future(test2(i)) for i in url]
start = time.time()
loop.run_until_complete(asyncio.wait(task))
endtime = time.time()-start
print(endtime)
loop.close()
- 异步的语法糖async 和 await需要配合使用
- 在async中的await方法后接awaitable的函数,否则报错
- asyncio模块提供时间循环get_even_loop时间循环支持多个异步函数
- 另loop事件循环支持call_back回调函数
- asyncio的Feature也是awaitable