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、生产者消费者模型——关闭消费者的另外一个方法

效果如下:

 

posted on 2019-05-06 21:02  江湖乄夜雨  阅读(167)  评论(0编辑  收藏  举报