Python学习笔记(十二)ThreadLocal及分布式进程

参考资料:https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832845200f6513494f0c64bd882f25818a0281e80000

1、ThreadLocal:提供在线程间独立操作外部变量的方式。直接看代码:

import threading

localobj = threading.local()

def print_student():
    print "student name in thread(%s) is %s" % (threading.current_thread().name, localobj.student)


def process_thread(name):
    localobj.student = name
    print_student()
#测试TheadLocal特性
def Test():
    localobj.student = 'MyName'
    t1 = threading.Thread(target=process_thread, args=('Tom',), name = 'ThreadA')
    t2 = threading.Thread(target=process_thread, args=('Alice',), name = 'ThreadB')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print "student name in mainthread is", localobj.student

2、在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上(Python不支持)。

3、分布式进程:Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,依靠网络通信将任务分布到其他多个进程中。参考资料中给出的代码在Windows操作系统下会报错,下面是基于参考资料代码修改后在Windows操作系统下测试通过的代码

(1)服务器进程:用于发布任务和搜集分布式运行结果。

# -*- coding: utf-8 -*-
import random, time, Queue
from multiprocessing.managers import BaseManager
from multiprocessing import *

# 用于网络共享的任务序列和结果队列
task_queue = Queue()
result_queue = Queue()

# 从BaseManager继承的QueueManager:
class QueueManager(BaseManager):
    pass
# 注意:下面的2个方法是针对Windows操作系统所作的修改,用于适应Lambda表达式无法Picle的问题(序列化)
def getTaskQueue():
    #print 'getTaskQueue'
    global task_queue
    return task_queue

def getResultQueue():
    #print 'getResultQueue'
    global result_queue
    return result_queue
#定义一个方法,用于发布任务
def putTask(manager):
    # 获得通过网络访问的Queue对象:
    try:
        task = manager.get_task_queue()
    except BaseException, e:
        print 'Failure to get TaskQueue:', e.message
        return 0
    # 放几个任务进去:
    for i in range(10):
        n = random.randint(0, 10000)
        print('Put task %d...' % n)
        task.put(n)
#定义一个方法,用于搜集结果
def getResult(manager):
    # 获得通过网络访问的Queue对象:
    try:
        result = manager.get_result_queue()
    except BaseException, e:
        print 'Failure to get ResultQueue:', e.message
        return 0
    # 从result队列读取结果:
    print('Try get results...')
    for i in range(10):
        try:
            r = result.get(timeout=10)
            print('Result: %s' % r)
        except BaseException, e:
            print 'Result Queue is Empty.', e.message
#主要的测试方法
def Test():   
    # 把两个Queue都注册到网络上, callable参数关联了Queue对象:原来的代码用到Lambda表达式,现在改成了自定义方法
    QueueManager.register('get_task_queue', callable = getTaskQueue)
    QueueManager.register('get_result_queue', callable = getResultQueue)
    # 绑定端口5000, 设置验证码'abc':原来的代码采用明码,现在改为b'abc'。
    manager = QueueManager(address=('127.0.0.1', 5000), authkey=b'abc')
    # 启动Queue:
    manager.start()
    #manager.get_server().server_forever()
    putTask(manager)
    getResult(manager)
    manager.shutdown() 

if __name__ == '__main__':
    freeze_support()
    Test()

(2)客户端进程:接收任务,并将本地处理结果写入共享的结果队列。

# -*- coding: utf-8 -*-
import time, sys, Queue
from multiprocessing.managers import BaseManager
from multiprocessing import *

# 创建类似的QueueManager:
class QueueManager(BaseManager):
    pass

# 由于这个QueueManager只从网络上获取Queue,所以注册时只提供名字:
QueueManager.register('get_task_queue')
QueueManager.register('get_result_queue')

def Test():
    # 连接到服务器,也就是运行taskmanager.py的机器:
    server_addr = raw_input('input server address:')
    if server_addr == '':
        server_addr = '127.0.0.1'
    print('Connect to server %s...' % server_addr)
    # 端口和验证码注意保持与服务器进程设置的完全一致:
    m = QueueManager(address=(server_addr, 5000), authkey=b'abc')
    # 从网络连接:
    m.connect()
    # 获取Queue的对象:
    task = m.get_task_queue()
    result = m.get_result_queue()
    # 从task队列取任务,并把结果写入result队列:
    for i in range(10):
        try:
            n = task.get(timeout=1)
            print('run task %d * %d...' % (n, n))
            r = '%d * %d = %d' % (n, n, n*n)
            time.sleep(1)
            result.put(r)
        except BaseException:
            print 'task queue is empty.'
    # 处理结束:
    print('worker exit.')

if __name__ == '__main__':
    freeze_support()
    Test()

(3)先在服务器上运行服务器进程,然后在客户端运行客户端进程,客户端进程监听服务器任务队列并根据队列信息执行本地任务,将执行结果写入结果队列;服务器进程监听结果队列,将结果队列内容从服务器输出。也可在同一台机器上同时分别运行2个进程。

今天就学习到这里啦,下一节从正则表达式学起。

没有更多推荐了,返回首页