进程,线程和协程

概念

进程:进程是一种抽象概念。是计算机资源分配的最小单元。由程序,数据集合和进程控制块(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
posted @ 2021-04-06 14:53  gege4105  Views(54)  Comments(0Edit  收藏  举报