python 多线程
每个程序运行一般会包含多个线程,对于python而言,它的多线程一般都是对于IO密集型程序较为有效,因为其存在全局解释器锁GIL,所谓的全局解释器锁,也就是只允许主循环中只有一个线程在运行。但对于计算密集型的程序python的多线程就没有什么意义了。
全局解释器锁的应用主要是为了保证数据安全,不出差错。当多个线程同时对一个数据访问时,就会出错。比如我们用50个线程向同一个账户存入1块钱时。当不使用锁时。
import time
from threading import Thread
def show_time(func): # 设置一个修饰器
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f'程序运行耗费时间{end - start}')
return wrapper
class Account():
def __init__(self):
self.all_money = 0
@property
def show_money(self):
return self.all_money
def add_money(self, deposite_money):
all_money = deposite_money + self.all_money # 此处重点 当你把此处改为self.all_money += deposite_money 是返回的数据其实还是安全的
#正是因为此处导致结果偏差,此时线程是不安全的
time.sleep(0.01)
self.all_money = all_money
class Deposite_Money(Thread):
def __init__(self, acount, deposite_money):
super().__init__()
self.acount = acount
self.deposite_money = deposite_money
def run(self):
self.acount.add_money(self.deposite_money)
@show_time
def main():
threads = []
my_acount = Account()
for i in range(50):
a = Deposite_Money(my_acount, 1)
threads.append(a)
a.start()
for thread in threads:
thread.join()
print(f'账户余额总数为{my_acount.show_money}')
if __name__ == '__main__':
main()
以下的代码是使用锁之后的
from threading import Thread, Lock
import time
def show_time(func): # 创建一个修饰器显示程序运行时间
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f'程序运行耗费{end - start}秒')
return wrapper
class Account():
"""
加锁类
这种类一般会用在线程类上
"""
def __init__(self):
self.all_money = 0
self.lock = Lock()
@property # 修饰器 保护all_money数据,对外只显示show_money接口
def show_money(self):
return self.all_money
def add_money(self, deposite_money): # 此时的deposite_money没有初始化,需要外部导入
self.lock.acquire() # 加上线程锁
try:
self.all_money += deposite_money
time.sleep(0.05)
finally:
self.lock.release() # 解锁
class Deposit_Money(Thread):
"""
创建一个线程类
先是初始化__init__()
接着使用run()完成相关操作
"""
def __init__(self, acount, deposite_money):
super().__init__()
self.acount = acount # 直接导入一个类的实例
self.deposite_money = deposite_money
def run(self):
self.acount.add_money(self.deposite_money)
@show_time
def main():
threads = []
my_count = Account()
for thread in range(50): # 用for循环创建50个线程
a = Deposit_Money(my_count, 1)
threads.append(a)
a.start()
for thread in threads:
thread.join() # 阻塞直到全部线程运行结束
print(f'账户余款总数为:{my_count.show_money}')
if __name__ == '__main__':
main()
除了存钱的例子外,还有比如我使用一个线程对一个列表进行赋值,同一时间用另一个线程对同一个列表进行打印print()此时就会发现打印出来的可能就只是半个刚刚赋值的列表,这种情况也是冲突的。
对于函数的一些零散的应用,如map()和reduce()内置函数,map()函数有两个参数,第一个是函数,第二个一般是列表,返回的结果是对应值在函数中作用的结果。比如
def multi(x):
return x**2
map(multi, [1, 3, 4, 5])
print(list(map(multi, [1, 3, 4, 5]))
# 结果会是 1, 9, 16, 25
map(int, input().split())
#一个个整数
而reduce中也是两个参数,一个函数,一个常为列表,但这个函数要两个参数,返回的结果为f(f(f(x1, x2), x3), x4)类型。
还有就是lambdas 的使用,comp = lambads x,y: x<y 若真就返回True,反之False.
在这吐槽一下那个不知怎么就热起来的秋天的第一杯奶茶,对我来说秋天的第一杯奶茶是是高攀不起了,但是再等等,我应该可以吃到冬天的第一口西北风。