一、进程池线程池(*****)

无论是开进程还是开线程都消耗资源,开线程比开进程消耗的资源要小

1、池:为了减缓计算机硬件的压力,避免计算机硬件设备崩溃。虽然减轻了计算机的压力,但是一定程度上降低了持续的效率

2、为什么要用“池”: 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务

3、进程池线程池:为了限制开设的进程数和线程数,从而保证计算机硬件的安全

4、池子内什么时候装进程:并发的任务属于计算密集型

池子内什么时候装线程:并发的任务属于IO密集型

①进程池

from concurrent.futures import ProcessPoolExecutor
import time, os, random

def task(x):
    print('%s 接客' % os.getpid())
    time.sleep(random.randint(2, 5))
    return x**2

if __name__ == '__main__':
    p = ProcessPoolExecutor(5)   # ()内不加参数默认开启的进程数是cpu的核数
    for i in range(20):
        p.submit(task, i)

②线程池

from concurrent.futures import  ThreadPoolExecutor
import time,random

def task(x):
    print('%s 接客' % x)
    time.sleep(random.randint(2, 5))
    return x ** 2

if __name__ == '__main__':
    p = ThreadPoolExecutor(4)  # ()内不加参数默认开启的线程数是cpu的核数*5
    for i in range(20):
        p.submit(task, i)

 

二、同步异步阻塞非阻塞(*****)

1、同步与异步:提交任务的两种方式

同步调用:提交完任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码

异步调用:提交完任务后,不在原地等待,直接执行下一行代码

from concurrent.futures import ThreadPoolExecutor
import time, random

def task(x):
    print('%s 接客' % x)
    time.sleep(random.randint(1, 3))
    return x ** 2

# 异步调用
if __name__ == '__main__':
    p = ThreadPoolExecutor(4)  # 默认开启的线程数是cpu的核数*5
    obj_l = []
    for i in range(10):
        obj = p.submit(task, i)
        obj_l.append(obj)
    p.shutdown(wait=True)      # 等待所有任务运行完毕在执行结果obj调result(),这里拿结果不同等待
    print(obj_l[0].result())
    print('')


# 同步调用
if __name__ == '__main__':
    p = ThreadPoolExecutor(4)  # 默认开启的线程数是cpu的核数*5
    for i in range(10):
        res = p.submit(task, i).result()    # 提交任务在原地等结果,与阻塞没有关系。
                                            # 拿到结果之后再继续执行
        print(res)
    print('')

2、阻塞与非阻塞:程序的两种运行状态 

阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源

非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地执行其他操作,力求尽可能多的占有CPU

 

三、协程(单线程下实现并发)

1、并发实现的本质:切换+保存状态

2、并发:看起来是同时运行,切换+保存状态

  并行:真正意义上的同时运行,只有在多cpu的情况下才能 实现并行,4个cpu能够并行4个任务

  串行:一个人完完整整地执行完毕才运行下一个任务

  协程:单线程下实现并发,自己通过代码层面监测自己的io行为, 并自己实现切换+保存状态,让操作系统误认为这个线程没有io

 ①客户端

from threading import Thread, current_thread
import socket

def client():
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    n = 1
    while True:
        data = '%s %s' % (current_thread().name, n)
        n += 1
        client.send(data.encode('utf-8'))
        info = client.recv(1024)
        print(info)

if __name__ == '__main__':
    for i in range(100):
        t = Thread(target=client)
        t.start()

②服务端

from gevent import monkey; monkey.patch_all()
from gevent import spawn
import socket

def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            print(data.decode('utf-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()

def server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communicate, conn)

if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()

 

四、gevent模块使用

from gevent import monkey; monkey.patch_all()   监测代码中所有io行为

from gevent import monkey; monkey.patch_all()  # 监测代码中所有io行为
from gevent import spawn
# gevent本身识别不了time.sleep等不属于该模块内的io操作
import time

def heng(name):
    print('%s 哼' % name)
    time.sleep(2)
    print('%s 哼' % name)

def ha(name):
    print('%s 哈' % name)
    time.sleep(2)
    print('%s 哈' % name)

start = time.time()
s1 = spawn(heng, 'egon')
s2 = spawn(ha, 'tank')

s1.join()
s2.join()
print('', time.time()-start)
# 结果为
# egon 哼
# tank 哈
# egon 哼
# tank 哈
# 主 2.1111209392547607