1. 多线程的基本使用

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.')
# 对函数 run 创建5个线程
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 开始线程活动
t.start() time.sleep(0.01)
print('Main thread is finished.')
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Main thread is finished.
Thread is finished. # 上面打印的顺序是先打印 Main thread is finished.因为主线程已经完成了,而子线程里 slee(3),所以此时子线程尚未完成,大约3秒后,才打印的 Thread is finished.

PS. 线程类的使用

import threading
import time num = 0
lock = threading.Lock() # 互斥锁,因为多个线程要对共享的数据:num 进行修改,防止出现错误。 class MyThread(threading.Thread): # 继承线程类
def __init__(self):
super().__init__() # 写了__init__,就一定要继承父类的构造方法。父类的__init__的参数是默认参数,故可以不用重写父类的参数。 def task(self): # 自定义的函数
global num
if lock.acquire(): # 如果上锁成功,则执行:
num+=1
print(f'{self.name}, Num is : {num}') # 打印线程名和num的值
lock.release() # 释放锁,让数据供其他线程使用
time.sleep(1) def task2(self):
time.sleep(0.1)
print(f'{self.name}','Task2 is being called.')
time.sleep(1) def run(self): # 重写父类的run方法。每个单独的线程控制中,start()会自动调用 run()方法。
self.task()
self.task2() for i in range(10):
T = MyThread() # 针对每个线程对象,start()最多只能调用一次,否则会抛出错误。所以才每循环一次,在循环内部重新生成一个对象
T.start()

2. 等待子线程执行:join

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.') Tlist = []
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 开始线程活动
t.start()
Tlist.append(t) for t in Tlist: # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
# t.join(0.1) # 针对每个子线程,等待0.1秒,继续执行主线程
t.join() # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。 time.sleep(0.01)
print('Main thread is finished.')
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Thread is finished.
Main thread is finished. # 子线程使用了join方法,等待子线程执行完毕才继续执行主线程,所以打印顺序是正常的。

3. 守护线程

即只要主线程执行完毕,不管子线程状态如何,都会被强制杀掉。

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.') Tlist = []
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 设置为守护线程
t.setDaemon(True)
# 开始线程活动
t.start()
Tlist.append(t) for t in Tlist: # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
t.join(0.1) # 对子线程等待0.1秒后,继续执行主线程
# t.join() # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。 time.sleep(0.01)
print('Main thread is finished.')
print('Current Thread:',threading.activeCount()) # 打印当前活动线程数量,这是主线程最后一个语句,所以不管此时还有多少个活动的守护线程,当此句执行完毕,守护线程都会被杀掉。
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Main thread is finished.
Current Thread: 6 # 少打印了 Thread is finished. 因为 主线程结束后,子线程就被杀掉了。

4. 线程锁

GIL锁:  Global Interpreter Lock,全局解释器锁。为了解决多线程之间数据完整性和状态同步的问题,在任意时刻只有一个线程在解释器中运行。这是CPython中的问题。

线程安全:在多线程中,共享的数据同一时间只能由一个线程执行。

互斥锁:(threading.Lock) 并不关心当前是哪个线程占有了该锁;如果该锁已经被占有了,那么任何其它尝试获取该锁的线程都会被阻塞,包括已经占有该锁的线程也会被阻塞。

递归锁:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源(已经占用该锁的线程,可以多次actuire,并不会阻塞)

死锁:死锁就是当一个线程已经占用了锁并且尚未释放,但是又有新的获取该锁的请求,亦或着两个线程分别占据着对方想要获取的锁,此时线程进入了阻塞的状态,就是死锁。

部份转自:https://www.jb51.net/article/74426.htm

部份转自:https://www.cnblogs.com/ArsenalfanInECNU/p/10022740.html

e.g.

互斥锁:threading.Lock

import threading

class MyThread(threading.Thread):
def run(self): # 这是重写的父类的run方法
global num
if mutex.acquire(): # 判断能否加锁,acquire()返回的是加锁的状态,加锁成功就是True
num = num+1
msg = self.name+' set num to '+str(num)
print(msg)
# mutex.acquire() # 这两句话如果不注释掉,就会进入死锁的状态。因为上一个锁还未释放,再次请求加锁,就会阻塞。
# mutex.release()
mutex.release() # 释放锁
num = 0
mutex = threading.Lock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()

普通方法:

import threading
import time def run(n):
global num
if mutex.acquire(): # 返回获取锁的结果,加锁成功为True,失败false
num = num+1
msg ='Thread-%s set num to ' %n + str(num)
print(msg)
mutex.release()
time.sleep(2) num = 0
mutex = threading.Lock() for i in range(5):
t = threading.Thread(target=run,args=(i+1,))
t.start()

递归锁:threading.RLock

import threading

class MyThread(threading.Thread):
def run(self):
global num
if mutex.acquire():
num = num+1
msg = self.name+' set num to '+str(num)
print(msg)
mutex.acquire() # 虽然再次acquire,但是并不会阻塞
mutex.release()
mutex.release()
num = 0
mutex = threading.RLock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()

5. 信号量 semaphore

信号量用于限制同时运行的线程数量

import threading
import time def run(n):
sema.acquire()
print('Thread: %s' %n)
time.sleep(2)
sema.release()
# 声明信号量,同时允许5个线程执行
sema = threading.BoundedSemaphore(5) for i in range(20):
t = threading.Thread(target=run,args=(i+1,))
t.start()

6. 事件:Event

事件可以用于多个线程进行简单通讯,事件可以控制一个内部 flag,初始时是 False,通过 set 方法使其变成 True,clear 方法使其变成 False,flag 为 False 时 wait 方法会一直阻塞直到flag 为True。

import threading
import time # 事件可以控制一个内部标志,通过set方法使其变成True,clear方法使其变成False,为False时wait方法会一直阻塞直到标志为True。
# 这个标志初始时是False event = threading.Event()
# event.set() # 设置flag为True
# event.clear() # 设置flag为False
# event.wait() # 一直等待(阻塞),直到有线程使用 set 方法将 flag 变成 True
# event.is_set() # 返回flag的值 def boss():
print('Boss: 今天加班5秒钟')
event.clear() # 清除 flag,使其值变为 false
time.sleep(5)
print("Boss: 时间到了,大家回家吧")
event.set() # 设置 flag,使其值变为 True def employee():
while True:
if event.is_set(): # 判断:如果 flag 为 True
print('Employee: 回家了!')
break
else:
print('Emplyee: 工作中,请勿打扰...')
event.wait() # 如果 flag 为 False,则使用 wait 方法一直等待,直到有线程将其设置为 True # 创建两个线程,分别为boss和employee,让它们根据 event 进行简单的通讯
b = threading.Thread(target=boss,)
e = threading.Thread(target=employee,)
b.start()
e.start()
结果:
Boss: 今天加班5秒钟
Emplyee: 工作中,请勿打扰...
Boss: 时间到了,大家回家吧
Employee: 回家了!

python 多线程、线程锁、事件的更多相关文章

  1. Python多线程-线程锁

    多线程修改一份数据时需要用到线程锁,以防止数据修改出错 #-*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threa ...

  2. 孤荷凌寒自学python第四十天python 的线程锁RLock

     孤荷凌寒自学python第四十天python的线程锁RLock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 因为研究同时在多线程中读写同一个文本文件引发冲突,所以使用Lock锁尝试同步, ...

  3. 孤荷凌寒自学python第三十九天python 的线程锁Lock

    孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...

  4. 第十五章、Python多线程同步锁,死锁和递归锁

    目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...

  5. Python学习---线程锁/信号量/条件变量同步/线程池1221

    线程锁 问题现象: 多线程情况下,CPU遇到阻塞会进行线程的切换,所以导致执行了tmp-=1的值还未赋值给num=tmp,另一个线程2又开始了tmp -=1,所以导致最后的值重复赋值给了num,所以出 ...

  6. python多线程中锁的概念

    1 2 3 4 5 6 7 8 mutex = threading.Lock() #锁的使用 #创建锁 mutex = threading.Lock() #锁定 mutex.acquire([time ...

  7. c++11多线程---线程锁(mutex)

    #include<mutex> 包含四类锁: 1      std::mutex    最基本也是最常用的互斥类 2      std::recursive_mutex  同一线程内可递归 ...

  8. python多线程--线程同步

    如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步. 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire ...

  9. 并发编程~~~多线程~~~线程queue, 事件event,

    一 线程queue 多线程抢占资源,只能让其串行. 互斥锁 队列 import queue q = queue.Queue() # 先进先出 q = queue.LifoQueue() # 先进后出 ...

  10. python的线程锁

    1.先看一个例子,一个进程可以起多个线程,多个线程都共享这个线程的内存 import threading import time num = 100 thread_lock = threading.L ...

随机推荐

  1. 浏览器端-W3School-JavaScript-Browser: Navigator 对象

    ylbtech-浏览器端-W3School-JavaScript-Browser: Navigator 对象 1.返回顶部 1. Navigator 对象 Navigator 对象 Navigator ...

  2. Linux 下 *.tar.gz 文件解压缩命令及错误处理

    1.压缩命令: 命令格式: tar -zcvf 压缩文件名 .tar.gz 被压缩文件名 可先切换到当前目录下,压缩文件名和被压缩文件名都可加入路径. 2.解压缩命令: 命令格式: tar -zxvf ...

  3. Custom Configuration 的两种方法:2.XmlSerializer XmlAttribute

    第二种:XmlSerializer XmlAttribute 1.CustomConfiguration.xml 2.CustomConfigurationSetting.cs 3.CustomCon ...

  4. java下载文件时文件名出现乱码的解决办法

    转: java下载文件时文件名出现乱码的解决办法 2018年01月12日 15:43:32 橙子橙 阅读数:6249   java下载文件时文件名出现乱码的解决办法: String userAgent ...

  5. os, sys, stat 模块使用

    1.设置文件权限: 注意:设置权限之前要导入下面三个模块,否则报错, import os, sys, stat os.chmod("/home/a.txt", stat.S_IXG ...

  6. python2.X与3.X比较及Python编译器选择

  7. DNS的解析流程

    一.简单理解 DNS服务器里存着一张表,表中放着域名和IP地址,域名和IP地址以映射关系保存,即一对一 浏览器访问某个域名,实际上是访问它的ip地址 所以浏览器需要知道域名对应的ip地址,由此产生dn ...

  8. Akka系列(九):Akka分布式之Akka Remote

    前言.... Akka作为一个天生用于构建分布式应用的工具,当然提供了用于分布式组件即Akka Remote,那么我们就来看看如何用Akka Remote以及Akka Serialization来构建 ...

  9. windeployqt.exe 发布windows下qt产生的exe程序

    以官方 Qt 5.4.0+MinGW 开发环境为例,从开始菜单-->Qt 5.4.0-->5.4-->MinGW 4.9 (32-bit)-->Qt 5.4 for Deskt ...

  10. CDH管理节点扩容磁盘步骤

    把4个节点加12G内存,把hive的heap调到6G,按group重启服务让配置生效 注: 停服务前在yarn的application webui查flink的application id yarn ...