Python多线程使用和注意事项
多线程 基本实现: 第一种,函数方式 # -*- 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]
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄
更多精彩