Python Cookbook中关于并发的例子
1、自定义线程terminal方法
# -*- coding:utf-8 -*- import time from threading import Thread class MyThread(object): def __init__(self): self.__running = True def terminal(self): self.__running = False def run(self,num): while self.__running and num > 0: print(num) num -= 1 time.sleep(1) if __name__ == '__main__': mt = MyThread() t = Thread(target=mt.run,args=(1000,)) t.start() time.sleep(5) mt.terminal()
效果:5秒后线程“自动关闭”
2、基于线程池实现并发的socket Server端
server端:
# -*- coding:utf-8 -*- from socket import socket,AF_INET,SOCK_STREAM from concurrent.futures import ThreadPoolExecutor def echo_client(client_sock,client_addr): print('Got connection from',client_addr) while 1: msg = client_sock.recv(65105).decode('utf-8') if not msg: break print('client msg:',msg) client_sock.sendall(msg.swapcase().encode('utf-8')) ## 注意client_addr是一个元组~~单个元组格式化的坑! print('Client %s close connection...'%((client_addr,))) client_sock.close() def server(addr): # 实例化线程池对象 t_pool = ThreadPoolExecutor(3) # 创建与初始化server对象 server = socket(AF_INET,SOCK_STREAM) server.bind(addr) server.listen() # 连接循环 while 1: client_sock,client_addr = server.accept() # 线程池中加与客户端通信的循环!!! t_pool.submit(echo_client,client_sock,client_addr) if __name__ == '__main__': addr = ('127.0.0.1',15000) server(addr)
client端:
# -*- coding:utf-8 -*- from socket import socket,AF_INET,SOCK_STREAM client = socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',15000)) while 1: msg = input('>>>:').strip() if not msg:break client.sendall(msg.encode('utf-8')) content = client.recv(65105).decode('utf-8') print('Server data:',content) client.close()
3、利用QUeue手动实现线程池的效果(用ThreadPoolExecutor实现!这样的优势在于使得任务的提交者能够更容易从调用函数中取得结果)
server端:
# -*- coding:utf-8 -*- from queue import Queue from threading import Thread from socket import socket,AF_INET,SOCK_STREAM def echo_client(q): sock,client_addr = q.get() print('Got connection from',client_addr) while 1: msg = sock.recv(65105).decode('utf-8') if not msg: print('Client %s closed connection'%((addr,))) break print('Client %s data:%s'%(addr,msg)) sock.sendall(msg.swapcase().encode('utf-8')) sock.close() def server(addr,max_num): # 实例化Queue对象 q = Queue() # 开线程 for i in range(max_num): # 须设置成守护线程——可以在实例化的时候用关键字参数设置 t = Thread(target=echo_client, args=(q,)) t.daemon = True t.start() # 运行server端 server = socket(AF_INET,SOCK_STREAM) server.bind(addr) server.listen() while 1: client_sock,client_addr = server.accept() q.put((client_sock,client_addr)) if __name__ == '__main__': addr = ('127.0.0.1',15001) server(addr,2)
client端:
# -*- coding:utf-8 -*- from socket import socket,AF_INET,SOCK_STREAM client = socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',15001)) while 1: msg = input('>>>:').strip() if not msg: break client.sendall(msg.encode('utf-8')) content = client.recv(65105).decode('utf-8') print('Server data:',content) client.close()
4、利用线程池获取网页中的数据并写到本地的文件
# -*- coding:utf-8 -*- import urllib.request from concurrent.futures import ThreadPoolExecutor def fetch_url(url): u = urllib.request.urlopen(url) data = u.read() return data if __name__ == '__main__': t_pool = ThreadPoolExecutor(2) url_lst = ['http://www.baidu.com','http://www.processon.com'] ret = [] for url in url_lst: t = t_pool.submit(fetch_url,url) ret.append(t) #等待任务全执行完 t_pool.shutdown() # 处理数据 for i in ret: data = i.result() # 文件的名字按照ret的索引位置来命名 f = open('url-%si.html'%(ret.index(i)+1), 'wb') f.write(data) f.close()
5、生产者消费者模型——关闭消费者的另外一个方法
效果如下: