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]