1. 多线程的实现方式
第一种是调用方法
import threading
import time
def get_detail_html(url):
print("get detail html ")
time.sleep(2)
print("get detail html end")
def get_detail_url(url):
print("get detail url ")
time.sleep(2)
print("get detail url end")
if __name__=="__main__":
thread1 = threading.Thread(target=get_detail_html, args=("",))
thread2 = threading.Thread(target=get_detail_url, args=("",))
start_time = time.time()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
# 主线程提出时候, 子线程kill掉
print("last time: {}".format(time.time() - start_time))
第二种是使用类继承threading.Thread
class GetDetailHtml(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
def run(self):
print("get detail html started")
time.sleep(2)
print("get detail html end")
class GetDetailUrl(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
def run(self):
print("get detail url started")
time.sleep(4)
print("get detail url end")
if __name__=="__main__":
thread1 = GetDetailHtml("get_detail_html")
thread2 = GetDetailUrl("get_detail_url")
start_time = time.time()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
# 主线程提出时候, 子线程kill掉
print("last time: {}".format(time.time() - start_time))
2. Python的全局解释器锁(GIL)
一直以来都感觉用python开发的时候运行速度挺慢的,其实有时候是它在影响, 下面代码开启两个线程,一个加1000000次一个减1000000次,结果每次执行结果都是不一样的
#gil global interpreter lock (cpython)
#python中一个线程对应于c语言中的一个线程
#gil使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行
#gil会根据执行的字节码行数以及时间片释放gil,gil在遇到io的操作时候主动释放
total = 0
def add():
global total
for i in range(1000000):
total += 1
def desc():
global total
for i in range(1000000):
total -= 1
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total) # 318676
3. 线程同步
使用锁使线程同步
from threading import Lock, RLock, Condition #可重入的锁
total = 0
lock = Lock()
def add():
global lock
global total
for i in range(1000000):
lock.acquire()
total += 1
lock.release()
def desc():
global total
global lock
for i in range(1000000):
lock.acquire()
total -= 1
lock.release()
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total) # 0
4. 重用锁
如果想要在一个方法里加上多个锁, Lock是做不到的就需要用RLock才可以重复用锁
from threading import Lock, RLock#可重入的锁
#在同一个线程里面,可以连续调用多次acquire, 一定要注意acquire的次数要和release的次数相等
total = 0
lock = RLock()
def add():
#1. dosomething1
#2. io操作
# 1. dosomething3
global lock
global total
for i in range(1000000):
lock.acquire()
lock.acquire()
total += 1
lock.release()
lock.release()
def desc():
global total
global lock
for i in range(1000000):
lock.acquire()
total -= 1
lock.release()
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
#
thread1.join()
thread2.join()
print(total) # 0
"""
5. 死锁的原因
伪代码解释一下死锁, A 调用
a
的, 同时 B 在掉用b
, A为了要执行下去 A 会调用b
, 但是B并没有释放b
, B又在等待A释放a
这样就会造成死锁
#1. 用锁会影响性能
#2. 锁会引起死锁
"""
A(a、b)
acquire (a)
acquire (b)
B(a、b)
acquire (b)
acquire (a)
网友评论