17.并发编程3

线程池和进程池

计算机开进程或者线程受限于计算机本身的硬件,所以就有了进程池和线程池限制最大进程或者线程数
不会造新的进程或者线程,不会浪费内存空间

进程池的使用
提交任务的两种方式:
同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行的
提交任务的方法,串行是任务的运行状态
异步调用:提交完一个任务之后,不在原地等待,结果???,而是直接执行下一行代码,会导致任务是并发执行的
提交任务的方法,并发是任务的运行状态

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

def task(name):
    print('%s %s is running'%(name,os.getpid()))
    time.sleep(random.randint(1,3))
    return 123

if __name__ == '__main__':
    # print(os.cpu_count())
    p = ProcessPoolExecutor(4)
    # 只会开4个进程的id
    # p.submit(task,'进程的pid')
    # p.submit(task,'进程的pid')
    # p.submit(task,'进程的pid')
    # p.submit(task,'进程的pid')
    # # 节约了再次开辟进程空间
    # p.submit(task,'进程的pid')
    # p.submit(task,'进程的pid')



#     同步调用,导致串行
# for i in range(20):
#     # p.submit(task,('进程的pid'))
#     future=p.submit(task,('进程的pid'))
#     # print(future)
#     # 同步调用
#     print(future.result())
#
# print('主')



#     异步调用,导致并发
l = []
for i in range(20):
    # p.submit(task,('进程的pid'))
    future=p.submit(task,('进程的pid'))
    l.append(future)
# #关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕
p.shutdown(wait=True)
for future in l:
    # 一次性全部拿到结果
    print(future.result())

print('主')

线程池的使用

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

# # 模拟下载
# # 谁闲下来了谁去解析
def get(i):
    print('%s 下载进程 %s'%(os.getpid(),i))
    time.sleep(3)
    parse(i)
def parse(i):
    print('%s 解析进程结果%s'%(os.getpid(),i))
    time.sleep(0.1)
if __name__ == '__main__':
    p = ProcessPoolExecutor(9)
    start = time.time()
    for i in range(9):
        future = p.submit(get,i)
    p.shutdown(wait = True)
    print('主',time.time() - start) # 4.617460250854492
    print('主',os.getpid())

get和parse耦合在一起,怎样实现解耦合?

def get(i):
    print('%s 下载进程 %s'%(os.getpid(),i))
    time.sleep(3)
    # parse(i)
    return i
def parse(i):
    i = i.result()
    print('%s 解析进程结果%s'%(os.getpid(),i))
    time.sleep(0.1)
if __name__ == '__main__':
    p = ProcessPoolExecutor(9)
    start = time.time()
    for i in range(9):
        future = p.submit(get,i)
        # 添加一个任务回收
        #         # 异步的9个进程会闲下来,闲下来的时候去做parse这个函数里面的事情
        # future.result()
        future.add_done_callback(parse)
        #  parse会在任务运行完毕后自动触发,然后接收一个参数future对象
        #         #         # 主进程处理解析,解析时间短,没必要去等下载完,由主进程一个(人)搞定
        #         #         # 其他子进程专心下载
    p.shutdown(wait = True)
    print('主',time.time() - start) # 4.617460250854492
    print('主',os.getpid())

io密集型,线程来做

from  threading import  current_thread
# io密集型,线程来做
def get(i):
    print('%s 下载线程 %s'%(current_thread().name,i))
    time.sleep(3)
    # parse(i)
    return i
def parse(i):
    i = i.result()
    print('%s 解析线程结果%s'%(current_thread().name,i))
    time.sleep(0.1)
if __name__ == '__main__':
    p = ThreadPoolExecutor(9)
    start = time.time()
    for i in range(9):
        future = p.submit(get,i)
        # 添加一个任务回收
        # 异步的9个线程会闲下来,闲下来的时候去做parse这个函数里面的事情
        # future.result()
        future.add_done_callback(parse)
        # 异步调用:提交完一个任务之后,不在原地等待,而是直接执行下一行代码,
        #         # 会导致任务是并发执行的,,结果futrue对象会在任务运行完毕后自动传给回调函数
        #         #  parse会在任务运行完毕后自动触发,然后接收一个参数future对象
        #         # 哪一个线程先结束下载就去处理解析,解析时间短,没必要去等其他线程下载完
    p.shutdown(wait = True)
    print('主',time.time() - start) # 4.617460250854492
    print('主',current_thread().name)

gevent模块实现协程并发

安装模块 pip install gevent -i https://pypi.tuna.tsinghua.edu.cn/simple gevent
安装模块 pip install 模块名 源不一定所有模块都有
3.6python解释器 3.8
-i https://pypi.tuna.tsinghua.edu.cn/simple gevent

from gevent import  monkey
# 所有的io行为进行打包
monkey.patch_all()
# 导入gevent管理的任务
from  gevent import  spawn,joinall
import time

def play(name):
    print('%s play 1'%name)
    time.sleep(5)
    print('%s play 2'%name)

def eat(name):
    print('%s eat 1'%name)
    time.sleep(3)
    print('%s eat 2'%name)

g1=spawn(play,'大海1')
g2=spawn(play,'大海2')
# 等待任务运行完
# g1.join()
# g2.join()
# 一行代码搞定
joinall([g1,g2])

# 主线程死了
print('主')

单线程实现并发的套接字通信

服务端
客户端关闭了服务端会正常结束
服务端必须满足至少三点:
绑定一个固定的ip和port
一直对外提供服务,稳定运行
能够支持并发,
因为是io密集型要开多线程

from gevent import  monkey
# 所有的io行为进行打包
monkey.patch_all()
# 导入gevent管理的任务
from  gevent import  spawn,joinall
# import time
import socket
def communicate(conn):
    # 通信循环
    while True:
        try:
            data = conn.recv(1024)
            print('收到客户端数据', data)

            # 变大写发送回去
            conn.send(data.upper())
        except Exception:
            break

def server(ip,port,backlog=5):
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind((ip,port))
    server.listen(backlog)
    while True:
        # 链接循环
        conn,client_addr = server.accept()
        # 通信循环
        spawn(communicate,conn)
        
if __name__ == '__main__':
    s = spawn(server,'127.0.0.1',8081)
    s.join()

客户端

from threading import Thread,current_thread
from socket import *

def client():
    client = socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',8081))
    n = 0
    while True:
        msg = '%s say hello %s'%(current_thread().name,n)
        n += 1
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        print(data.decode('utf-8'))

if __name__ == '__main__':
    for i in range(100):
        t = Thread(target=client)
        t.start()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值