1. 为什么需要线程锁?
多个线程对同一个数据进行修改时, 可能会出现不可预料的情况.
2. 如何实现线程锁?
# 1. 实例化一个锁对象;
# lock = threading.Lock()
# 2. 操作变量之前进行加锁
# lock.acquire()
# 3. 操作变量之后进行解锁
# lock.release()
线程锁在程序中运用
import threading
# 以银行存钱和取钱举例
def add(lock):
global money # 生命money为全局变量
for i in range(1000):
# 2. 操作变量之前进行加锁
lock.acquire()
money += 1
# 3. 操作变量之后进行解锁
lock.release()
def reduce(lock):
global money
for i in range(1000):
# 2. 操作变量之前进行加锁
lock.acquire()
money -= 1
# 3. 操作变量之后进行解锁
lock.release()
if __name__ == '__main__':
money=0
# 1. 实例化一个锁对象;
lock = threading.Lock()
t1 = threading.Thread(target=add, args=(lock,))
t2 = threading.Thread(target=reduce, args=(lock,))
t1.start()
t2.start()
t1.join()
t2.join()
print("当前金额:", money)
# 当使用继承来实现多线程
import threading
class AddThread(threading.Thread):
def __init__(self, lock):
super(AddThread, self).__init__()
self.lock = lock
def run(self):
for i in range(1000000):
# 2. 操作变量之前进行加锁
self.lock.acquire()
global money
money += 1 # money; money+1; money=money+1;
# 3. 操作变量之后进行解锁
self.lock.release()
class ReduceThread(threading.Thread):
def __init__(self, lock):
super(ReduceThread, self).__init__()
self.lock = lock
def run(self):
global money
for i in range(1000000):
# 2. 操作变量之前进行加锁
lock.acquire()
money -= 1
# 3. 操作变量之后进行解锁
lock.release()
if __name__ == '__main__':
money = 0
# 1. 实例化一个锁对象;
lock = threading.Lock()
t1 = AddThread(lock)
t2 = ReduceThread(lock)
t1.start()
t2.start()
t1.join()
t2.join()
print("当前金额:", money)
再比如实现多线程下载,以下是下载器的程序:
# 实现多线程的下载器
import threading
from urllib.request import urlopen
DOWNLOAD_DIR = 'doc'
class DownloadThread(threading.Thread):
def __init__(self, url):
super(DownloadThread, self).__init__()
self.url = url
def run(self):
try:
urlObj = urlopen(self.url)
except Exception as e:
print("download %s error\n" % (self.url), e)
imgContent = None
else:
filename = self.url.split("/")[-1]
# 'wb' === 写的是二进制文件(图片, 视频, 动图, .pdf)
# 'ab'
with open("%s/%s" % (DOWNLOAD_DIR, filename), 'ab') as f:
# 如果文件特别大的时候, 建议分块下载;每次只读取固定大小, 防止占用内存过大.
while True:
imgContentChunk = urlObj.read(1024 * 3)
if not imgContentChunk:
break
f.write(imgContentChunk)
# 可以添加下载的程度(百分率);
print("%s下载成功" % (filename))
url1='https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1566735794&di=37ecfaf0fa4f16f616b86be7b9a7091a&src=http://b-ssl.duitang.com/uploads/item/201808/27/20180827030547_tsblg.jpg'
url2='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1566745890473&di=364b5eca93978f39c8ae55000323d757&imgtype=0&src=http%3A%2F%2Fpic19.nipic.com%2F20120227%2F3145425_092317138000_2.jpg'
urls = [url1,url2]
for url in urls:
thread = DownloadThread(url)
thread.start()
thread.join()