1. 程式人生 > >Python多線程使用和註意事項

Python多線程使用和註意事項

col clas 函數 tran [] utf-8 阻塞 () courier

多線程 基本實現: 第一種,函數方式 # -*- coding:utf-8 -*- import thread import time def print_time(threadName, delay): count = 0 while count < 5: time.sleep(delay) count += 1 print ‘%s : %s‘ % (threadName, time.ctime(time.time())) try: thread.start_new_thread(print_time, ("Thread-1", 2,)) thread.start_new_thread(print_time, ("Thread-2", 4,)) except: print "Error!Unable to start thread." while 1: pass 第二種,繼承父類 # -*- coding:utf-8 -*- import threading import time class MyThread(threading.Thread): def __init__(self, thread_id, name, counter): threading.Thread.__init__(self) self.thread_id = thread_id self.name = name self.counter = counter def run(self): print "Starting:" + self.name print_time(self.name, self.counter, 5) print "Exiting:" + self.name def print_time(thread_name, delay, counter): while counter: time.sleep(delay) print ‘%s : %s‘ % (thread_name, time.ctime(time.time())) counter -= 1 thread1 = MyThread(1, "Thread-1", 1) thread2 = MyThread(2, "Thread-2", 2) thread1.start() thread2.start() 線程同步的問題解決:鎖 這裏第一個線程執行的時候,第二個線程是等待狀態的 # -*- coding:utf-8 -*- import threading import time threadLock = threading.Lock() threads = [] class MyThread(threading.Thread): def __init__(self, thread_id, name, counter): threading.Thread.__init__(self) self.thread_id = thread_id self.name = name self.counter = counter def run(self): print "Starting:" + self.name threadLock.acquire() print_time(self.name, self.counter, 5) print "Exiting:" + self.name threadLock.release() def print_time(thread_name, delay, counter): while counter: time.sleep(delay) print ‘%s : %s‘ % (thread_name, time.ctime(time.time())) counter -= 1 thread1 = MyThread(1, "Thread-1", 1) thread2 = MyThread(2, "Thread2", 2) thread1.start() thread2.start() threads.append(thread1) threads.append(thread2) for thread in threads: thread.join() 線程優先級隊列: 雖然開啟了多個線程,不過打印順序一定是:one按順序到five # -*- coding:utf-8 -*- import threading import time import Queue exit_flag = 0 queue_lock = threading.Lock() work_queue = Queue.Queue(10) thread_list = ["Thread-1", "Thread-2", "Thread-3"] name_list = ["one", "two", "three", "four", "five"] threads = [] thread_id = 1 class MyThread(threading.Thread): def __init__(self, thread__id, name, queue): threading.Thread.__init__(self) self.thread__id = thread__id self.name = name self.queue = queue def run(self): print "Starting:" + self.name process_data(self.name, self.queue) print "Exiting:" + self.name def process_data(thread_name, queue): while not exit_flag: queue_lock.acquire() if not work_queue.empty(): data = queue.get() queue_lock.release() print "%s processing %s" % (thread_name, data) else: queue_lock.release() time.sleep(2) for t in thread_list: thread = MyThread(thread_id, t, work_queue) thread.start() threads.append(thread) thread_id += 1 queue_lock.acquire() for word in name_list: work_queue.put(word) queue_lock.release() while not work_queue.empty(): pass exit_flag = 1 for t in threads: t.join() 這裏的join函數重點解釋下: join的原理就是依次檢驗線程池中的線程是否結束,沒有結束就阻塞主線程直到其他線程結束,如果結束則跳轉執行下一個線程的join函數
接下來看看多線程實際的案例: 多線程訪問網站 # -*- coding:utf-8 -*- import urllib2 import time from threading import Thread class GetUrlThread(Thread): def __init__(self, url): Thread.__init__(self) self.url = url def run(self): response = urllib2.urlopen(self.url) print self.url, response.getcode() def get_responses(): urls = [ ‘https://www.baidu.com‘, ‘https://www.taobao.com‘, ‘https://www.cnblogs.com‘, ‘https://github.com‘, ‘https://www.jd.com‘ ] start = time.time() threads = [] for url in urls: thread = GetUrlThread(url) threads.append(thread) thread.start() for thread in threads: thread.join() print "Time: % s" % (time.time() - start) get_responses() 如果多個線程訪問同一個變量,容易出問題,比如下面:
有可能最後的實際值並不是50 # -*- coding:utf-8 -*- from threading import Thread some_var = 0 class IncrementThread(Thread): def run(self): global some_var read_value = some_var print "線程%s中的some_var是%d" % (self.name, read_value) some_var = read_value + 1 print "線程%s中的some_var增加後變成%d" % (self.name, some_var) def use_increment_thread(): threads = [] for i in range(50): thread = IncrementThread() threads.append(thread) thread.start() for thread in threads: thread.join() print "在50次運算後some_var應該變成50" print "在50次運算後some_var實際值為:%d" % (some_var,) use_increment_thread() 解決辦法,加入一個鎖:
這種情況,最後的實際值一定是50 # -*- coding:utf-8 -*- from threading import Thread, Lock lock = Lock() some_var = 0 class IncrementThread(Thread): def run(self): global some_var lock.acquire() read_value = some_var print "線程%s中的some_var是%d" % (self.name, read_value) some_var = read_value + 1 print "線程%s中的some_var增加後變成%d" % (self.name, some_var) lock.release() def use_increment_thread(): threads = [] for i in range(50): thread = IncrementThread() threads.append(thread) thread.start() for thread in threads: thread.join() print "在50次運算後some_var應該變成50" print "在50次運算後some_var實際值為:%d" % (some_var,) use_increment_thread() 另一個鎖的案例: 不加鎖容易出事 # -*- coding:utf-8 -*- from threading import Thread import time class CreateListThread(Thread): def __init__(self): self.entries = [] Thread.__init__(self) def run(self): self.entries = [] for i in range(10): time.sleep(1) self.entries.append(i) print self.entries def use_create_list_thread(): for i in range(3): t = CreateListThread() t.start() use_create_list_thread() 結果: [[[000, , , 111, , , 222, , , 333, , , 444, , , 555, , , 666, , , 777, , , 888, , , 999]]] 給他加上鎖: # -*- coding:utf-8 -*- from threading import Thread, Lock import time lock = Lock() class CreateListThread(Thread): def __init__(self): self.entries = [] Thread.__init__(self) def run(self): self.entries = [] for i in range(10): time.sleep(1) self.entries.append(i) lock.acquire() print self.entries lock.release() def use_create_list_thread(): for i in range(3): t = CreateListThread() t.start() use_create_list_thread() 結果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Python多線程使用和註意事項