网络编程(七) 并发编程之socket服务端实现并发+协程

一. socket服务端实现并发(开多线程)

  

import socket
from threading import Thread
"""
服务端:
    1.固定的ip和port
    2.24小时不间断提供服务
    3.支持高并发
"""
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)  # 半连接池


def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)  # 阻塞
            if len(data) == 0:break
            print(data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()

while True:
    conn,addr = server.accept()  # 阻塞
    print(addr)
    t = Thread(target=communicate,args=(conn,))
    t.start()
import socket


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

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

二. 单线程下实现并发:开协程

服务端:

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()
# 原本服务端需要开启500个线程才能跟500个客户端通信,现在只需要一个线程就可以扛住500客户端
客户端:

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()

三.进程池线程池

      为了减缓计算机硬件的压力,避免计算机硬件设备崩溃,  从而限制开设的进程数和线程数.

       提交任务的方式:
       同步:提交任务之后,原地等待任务的返回结果,再继续执行下一步代码
       异步:提交任务之后,不等待任务的返回结果(通过回调函数拿到返回结果并处理),直接执行下一步操作

       回调函数: 异步提交之后一旦任务有返回结果,自动交给另外一个去执行

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


pool=ProcessPoolExecutor(5)

def task(n):
    print(n,os.getpid())
    time.sleep(2)
    return n*2

def call_back(n):
    print('get result:%s'%n.result())


if __name__ == '__main__':
    t_list=[]
    for i in range(20):
        future=pool.submit(task,i).add_done_callback(call_back)
        t_list.append(future)
    print('main')

四.协程: 通过代码层面自己监测io, 自己实现切换,让操作系统误认为这个线程没有io.

           那么切换+保存状态就一定能够提升你程序的效率吗?
           不一定,当你的任务是计算密集型,反而会降低效率,如果你的任务是IO密集型,会提升效率
           

from gevent import  monkey; monkey.patch_all()  #检测代码中所有io行为
from gevent import spawn
import time

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


def ha(name):
    print('%s 哈'%name)
    time.sleep(3)
    print('%s 哈' % name)
start = time.time()
s1 = spawn(heng,'egon')
s2 = spawn(ha,'echo')

s1.join()
s2.join()
# heng('egon')
# ha('kevin')

print('',time.time()-start)
加协程后原来5s缩短为3s


五.在来回切换过程中,计算密集型的任务执行时间比串行还长

# 串行执行
import time

def func1():
    for i in range(10000000):
        i+1

def func2():
    for i in range(10000000):
        i+1

start = time.time()
func1()
func2()
stop = time.time()
print(stop - start)
# 基于yield并发执行
import time
def func1():
    while True:
        10000000+1
        yield

def func2():
    g=func1()
    for i in range(10000000):

        i+1
        next(g)

start=time.time()
func2()
stop=time.time()
print(stop-start)

 

posted @ 2019-05-19 23:58  纵横捭阖行  阅读(434)  评论(0编辑  收藏  举报