在使用用的过程中需要导入threading模块的Lock类

使用锁:

  当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
  线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互 斥锁。 
  互斥锁为资源引入一个状态:锁定/非锁定。
 

锁的语法

  创建锁、锁定锁、释放锁

from threading import Lock

# 创建锁
mutex = Lock()
# 获取锁(上锁)
mutex.acquire()
# 释放锁(解锁)
mutex.release()

  在锁定锁的过程中acquire()方法可以接受一个blocking参数,

    如果设定blocking为True,则当前线程会堵塞,直到获取到这个锁为止(如果没有 指定,那么默认为True)

    如果设定blocking为False,则当前线程不会堵塞

  上锁和解锁的过程(假设是多线程调度):

    这个锁一般是为共享资源服务的,即多个线程同时使用共享资源。这个锁同一时间只能有一个线程调度,其他线程阻塞,只有当前调度的线程释放这个锁,阻塞的线程才能调度。

  锁的优点:

    确保了某段关键代码只能有一个线程从头到尾完整的执行。

  锁的缺点:

    组织了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大的降低了;代码中可能存在多个锁,如果多个线程拥有多个锁,容易造成死锁。

  死锁的现象(实例):

# 死锁 两者都没有释放对方需要的锁,而释放的条件恰好是获取对方释放所需要的锁
# 线程1
class MyThread1(threading.Thread):
def __init__(self):
super().__init__() def run(self):
# 线程1获取A锁
if mutexA.acquire():
print(self.name+"-----do1---up-----")
sleep(1)
# 此时线程2获取了B锁,需要等待线程2释放B锁
if mutexB.acquire():
print(self.name + "-----do1---down-----")
mutexB.release()
mutexA.release() # 线程2
class MyThread2(threading.Thread):
def __init__(self):
super().__init__() def run(self):
# 线程2获取B锁
if mutexB.acquire():
print(self.name + "-----do2---up-----")
sleep(1)
# 此时线程1获取了A锁,需要等待线程1释放A锁
if mutexA.acquire():
print(self.name + "-----do2---down-----")
mutexA.release()
mutexB.release() mutexA = threading.Lock()
mutexB = threading.Lock() if __name__ == '__main__':
# 线程1和线程2同时执行
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()

  避免死锁的方法:银行家算法

多进程与多线程比较及选择

是否采用多任务处理,取决于我们的任务类型

如果是计算密集型,需要大量的CPU资源进行运算,代码的运行效率至关重 要,这样的任务一般不使用多线程进行,因为频繁的任务调度会拖慢CPU的
运算。

如果是IO密集型,涉及到硬盘读写,网络读写等的任务,更多的时间在等待 IO操作完成,这一类任务可以放到多线程或多进程中来进行。

单线程、多线程、多进程(一起实现同一代码的时间)

# 单线程、多线程、多进程的使用及不同
# 简单的求和
def fib(x):
res = 0
for i in range(100000000):
res += i*x
return res # 阶乘
def fac(x):
if x < 2:
return 1
return x*fac(x-1) # 简单的求和
def sum(x):
res = 0
for i in range(50000000):
res += i*x
return res # 函数列表
funcs = [fib, fac, sum]
n = 100 class MyThread(threading.Thread):
def __init__(self, func, args, name=""):
super().__init__()
self.name = name
self.func = func
self.args = args
self.res = 0 def getResult(self):
return self.res def run(self):
print("starting ", self.name, " at: ", ctime())
self.res = self.func(self.args)
print(self.name, "finished at: ", ctime()) def main():
nfuncs = range(len(funcs)) print("单线程".center(30, "*"))
start = time()
for i in nfuncs:
print("start {} at: {}".format(funcs[i].__name__, ctime()))
start_task = time()
print(funcs[i](n))
end_task = time()
print("任务 耗时:", end_task-start_task)
print("{} finished at: {}".format(funcs[i].__name__, ctime())) end = time()
print("单线程运行时间:", end-start)
print("单线程结束:".center(30, "*")) print()
print("多线程".center(30, "*"))
start = time()
threads = []
for i in nfuncs:
# 一个线程绑定一个函数
t = MyThread(funcs[i], n, funcs[i].__name__)
threads.append(t) for i in nfuncs:
# 同时启动线程
threads[i].start() for i in nfuncs:
threads[i].join()
print(threads[i].getResult())
end = time()
print("多线程运行时间:", end-start)
print("多线程结束:".center(30, "*")) print()
print("多进程".center(30, "*"))
start = time()
process_list = []
for i in nfuncs:
# 一个进程绑定一个函数
t = Process(target=funcs[i], args=(n, ))
process_list.append(t) for i in nfuncs:
# 同时启动进程
process_list[i].start() for i in nfuncs:
process_list[i].join()
end = time()
print("多进程运行时间:", end - start)
print("多进程结束:".center(30, "*")) if __name__ == "__main__":
main()

最新文章

  1. 解密jQuery事件核心 - 模拟事件(四)
  2. 用最基本的EF+MVC+JQ+AJAX+bootstrap实现权限管理的简单实例 之登陆和操作权限
  3. iOS开发零碎知识点
  4. 科技部专家王涌天:移动AR头显将“让人类重新站起来”
  5. TextBox(只允许输入字母或者数字)
  6. JavaScript基础之函数与数组
  7. lintcode:快乐数
  8. Oracle varchar2 4000
  9. Meditation Guide
  10. RabbitMQ系列教程之四:路由(Routing)
  11. 用HTML5实现的各种排序算法的动画比較
  12. Java中Semaphore(信号量)的使用
  13. px妙转rem
  14. 实用的sublime插件集合 – sublime推荐必备插件
  15. MySQL学习(九)
  16. 关于 Javascript 严格模式下多文件合并时注意
  17. enter快捷键盘
  18. zabbix-agent 自动注册
  19. 判断ORACLE启动时使用spfile还是pfile
  20. matplotlib之legend

热门文章

  1. Windows 局域网内共享
  2. luoguP4393Sequence
  3. c# 第9节 数据类型之引用类型
  4. 201871010114-李岩松《面向对象程序设计(java)》第十三周学习总结
  5. day21_7.25 面向对象之继承
  6. 13-numpy笔记-莫烦pandas-1
  7. Subversion简介(一)
  8. 【oracle】ORA-12638 : 身份证明检索失败
  9. 两台三层交换机单区域OSPF动态路由实验
  10. 端口转发之 lcx