python中级第十九课--创建线程池(小白piao分享)

目的:

     我们想去创建一个工作者线程池来处理客户端的连接,让每个线程去处理各自的客户,或者完成其他类型的工作。

方法:

    在concurrent.futures库中包含了ThreadPoolExecutor类可以实现这个目的。下面的例子是一个简单TCP服务器,使用线程池来处理客户端:

from socket import AF_INET, SOCK_STREAM, socket
from concurrent.futures import ThreadPoolExecutor

def echo_client(sock, client_addr):
    print('Got connection from :', client_addr)
    while True:
        msg = sock.recv(65536)
        if not msg:
            break
        sock.sendall(msg)
    print(sock,'has been sent all message ...')
    sock.close()

def echo_server(addr):
    pool = ThreadPoolExecutor(128)
    sock = socket(AF_INET, SOCK_STREAM)
    sock.bind(addr)
    sock.listen()
    while True:
        client_sock, client_addr = sock.accept()#服务器接收客户端请求
        pool.submit(echo_client, client_sock, client_addr)# 提交给线程池中的处理函数去处理客户端
echo_server(('localhost',21000))# 服务器启动

    同样,可以抛开concurrent.futures中的ThreadPoolExecutor,直接手动创建线程池,如果借助Queue则会变得容易:

from socket import SOCK_STREAM, AF_INET,socket
from threading import Thread
from queue import Queue

def echo_client(q):
    sock, client_addr = q.get()
    print('got connection:', client_addr)
    while True:
        msg = sock.recv(65536)
        if not msg:
            break
        sock.sendall(msg)
    print('client close')
    sock.close()

def echo_server(addr, client_count):
    q = Queue()
    for x in range(client_count):
        t = Thread(target=echo_client,args=(q,),daemon=True)
        t.start()
    sock = socket(SOCK_STREAM, AF_INET)
    sock.bind(addr)
    sock.listen(5)
    while True:
        sock, client_addr = sock.accept()
        q.put(sock,client_addr)

    当然又有一句很蹩脚的话,不建议各位这样使用!!应该去使用concurrent.futures中的ThreadPoolExecutor,这么做的优势在于提交任务者可以很好地拿到处理后的结果:

from concurrent.futures import ThreadPoolExecutor
import urllib.request

def request_url(url):
    u = urllib.request.urlopen(url)
    data = u.read()
    return data

pool = ThreadPoolExecutor(10)
a = pool.submit(request_url,r'http://www.xxxxxx.com')
b = pool.submit(request_url,r'http://www.xxxxxx.org')
res1 = a.result()# 会阻塞等待上述中a取出结果后再解除阻塞
res2 = b.result()

    讨论一个大家都很容易想到的问题,有些人认为,应该在服务器接收到一个客户端连接时就去开辟一个线程来处理这个客户端的事务,本质上来讲这样确实没有问题,但是,万一一个黑客用大量的客户端去访问服务时,有可能会因为开辟太多线程导致服务器挂掉,这是初学者都会想到的思路,但是,一旦涉及多并发程序,切记一定要限制线程个数,为了系统稳定和安全。下面为各位展示初学者的代码;

from threading import Thread
from socket import socket, AF_INET, SOCK_STREAM

def echo_client(sock, client_addr):
    print('GOT a connection:', client_addr)
    while True:
        msg = sock.recv(65536)
        if not msg:
            break
        sock.sendall(msg)
    sock.close()

def echo_server(addr:tuple):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.bind(addr)
    sock.listen(5)
    while True:
        client_sock, client_addr = sock.accept()
        t = Thread(target=echo_client,args=(client_sock, client_addr))
        t.daemon = True
        t.start()

echo_server(('localhost',21000))

    这里也要注意,线程只适合做IO密集型的任务。综上关于线程池的内容就介绍到这里,如果想要了解更多请微信关注公众号:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白piao

创作不易,支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值