Day 36 socket并发,协程,进程池与线程池

一、socket并发

#服务端
import
socket from threading import Thread server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) def communcate(conn): while True: try: data = conn.recv(1024) if not data: break print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() while True: conn,addr=server.accept() print(addr) t=Thread(target=communcate,args=(conn,)) t.start()
#客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))


while True:
    info = input(">>>:").encode('utf-8')
    if not info:continue
    client.send(info)
    data=client.recv(1024)
    print(data.decode('utf-8'))

二、协程

协程:
进程:资源单位(车间)
线程:最小执行单位(流水线)
协程:单线程下实现并发

并发:看上去像同时执行就可以称之为并发

多道技术:
空间上的复用
时间上的复用
核心:切换+保存状态
协程:完全是我们高技术的人自己编出来的名词
通过代码层面自己监测io自己实现切换,让操作系统误认为
你这个线程没有io

切换+保存状态就一定能够提升你程序的效率吗?
不一定
当你的任务是计算密集型,反而会降低效率
如果你的任务是IO密集型,会提升效率
协程:单线程下实现并发
如果你能够自己通过代码层面监测你自己的io行为
并且通过代码实现切换+保存状态
串行执行纯计算操作
import time
def task1():
    res =1
    for i in range(1000000):
        res+=i

def task2():
    res=1
    for i in range(1000000):
        res*=i

stat=time.time()
task1()
task2()
stop =time.time()
print(stop-stat)
计算一段时间往上切,加上了来回切的时间
基于yiel保存状态,实现两个任务间来回切换,实现并发效果
yield并不能帮我们自动捕获到io行为才切换
import time
def task1():
    res =1
    for i in range(1000000):
        res+=i
        yield

def task2():
    g=task1()
    res=1
    for i in range(1000000):
        res*=i
        next(g)

stat=time.time()

task2()
stop =time.time()
print(stop-stat)

三、gevent模块

一个spawn就是一个帮你管理任务的对象
gevent模块不能识别它本身以外的所有的IO行为比如(time.sleep)
from gevent import monkey;monkey.patch_all()  #能够帮助我们识别所有的IO行为
from threading import current_thread
import gevent
import time
def eat():
    print('%s eat 1'%current_thread().name)
    # gevent.sleep(3)
    time.sleep(3)
    print('%s eat 2'%current_thread().name)
def play():
    print('%s play 1'%current_thread().name)
    # gevent.sleep(5)
    time.sleep(5)
    print('%s play 2'%current_thread().name)

g1 =gevent.spawn(eat) #异步提交
g2 =gevent.spawn(play)
print(current_thread().name)

g1.join()
g2.join()

四、进程池与线程池

1、为什么要用“池”:
池子是用来限制并发的任务数目,限制我们的计算机在一个自己承受的范围内去并发的执行任务
2、什么时候用进程池:
并发的任务属于计算密集型
3、什么时候用线程池:
并发的任务属于IO密集型

#进程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os,random

def task(x):
    print('%s 接客'%os.getpid())
    time.sleep(random.randint(2,3))
    return x**2
if __name__ == '__main__':
    p =ProcessPoolExecutor(max_workers=4) #默认开启进程数是cpu的核数
    for i in range(20):
        p.submit(task,i) #submit提交任务的方式,异步提交

#线程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os,random

def task(x):
    print('%s 接客'%x)
    time.sleep(random.randint(2,3))
    return x**2
if __name__ == '__main__':
    p =ThreadPoolExecutor(4) #默认开启(线程数=cpu核数*5左右)
    for i in range(20):
        p.submit(task,i) #submit提交任务的方式,异步提交

五、单线程下实现并发

#服务端
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import socket

def communicate(conn):
    while True:
        try:
            data =conn.recv(1024)
            if not data: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()
#客户端
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(500):
        t=Thread(target=client)
        t.start()

 

 
 
 
 

posted on 2019-05-09 20:51  ZY_LO  阅读(176)  评论(0编辑  收藏  举报

导航