參考資料: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個進程。
今天就學習到這裏啦,下一節從正則表達式學起。