参考资料: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个进程。
今天就学习到这里啦,下一节从正则表达式学起。