第三十三天- 线程创建、join、守护线程、死锁
1.线程,线程创建
概念:在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程,车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线。流水线的工作需要电源,电源就相当于cpu。
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
创建:
线程创建方式一:
from multiprocessing import Process
from threading import Thread def func(n):
print('xxxxx')
print('>>>',n) if __name__ == '__main__': # p = Process(target=func,args=(1,))
# p.start() t = Thread(target=func,args=(1,)) # 直接创建
t.start() print('主线程结束')
面向对象创建:
from threading import Thread # 面向对象创建
class Mythread(Thread): # 继承Thread父类 def __init__(self,xx):
super().__init__()
self.xx = xx def run(self): # 必须有run,覆盖父类run中的pass
print(self.xx)
print('我重置父类方法') def func1(self): # 写其他方法
print('我是func1') if __name__ == '__main__': t1 = Mythread('xx')
t1.start() # 默认执行run
t1.func1() # 调用其他方法
# from multiprocessing import Process
from threading import Thread
2.Thread类方法
join方法:
主线程等待join子线程执行完毕后才执行
import time
from threading import Thread def func(n):
time.sleep(n)
print('我是子线程') if __name__ == '__main__': t = Thread(target=func,args=(1,))
t.start() t.join() # 等待子线程执行结束
print('我是主线程,子线程结束再执行我')
join
其他方法:
''
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。 threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
'''
import time, threading
from threading import Thread, current_thread def func():
time.sleep(2)
print('子线程,名字是:', current_thread().getName()) # 返回线程名
print('子线程,ID是:', current_thread().ident) # 返回线程id if __name__ == '__main__': for i in range(10):
t = Thread(target=func, )
t.start() print(threading.enumerate()) # 返回一个包含正在运行的list
print(threading.activeCount()) # 返回正在运行的线程数量,等同len(threading.enumerate()) print('主线程结束')
其他方法示例
3.守护线程、事件
守护线程:
主进程结束,守护进程跟着结束,再执行非守护进程
主线程要等待所有非守护线程运行结束才会结束(因为他们属于同一进程)
需注意:运行结束并非终止运行
xxx.setDaemon(True) 或者 xxx.daemon = True
import time
from threading import Thread
from multiprocessing import Process def func1():
time.sleep(3)
print('任务1结束') def func2():
time.sleep(2)
print('任务2结束') if __name__ == '__main__': # p1 = Process(target=func1,)
# p2 = Process(target=func2,)
# # p1.daemon = True
# p2.daemon = True
# p1.start()
# p2.start()
#
# print('主进程结束') t1 = Thread(target=func1,)
t2 = Thread(target=func2,)
# t1.setDaemon(True) # 只打印出 主线程和t2 因为t2时间比t1小
t2.setDaemon(True) # 会正常打印出所有 因为t1时间大于t2
t1.start()
t2.start() print('主线程结束')
守护线程与守护进程
事件:
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
import time
from threading import Event e = Event() # 默认false状态
print(e.isSet()) # 事件当前状态 e.set() # 改变成Ture
print(e.isSet()) print('稍等...')
# e.clear() # 将e的状态改为False
e.wait() # 如果 event.isSet()==False将阻塞线程 if e.isSet() == True:
time.sleep(1)
print('滴滴滴,上车吧...')
事件代码示例
4.线程间数据问题
开启一个线程所需要的时间要远小于开启一个进程
import time
from multiprocessing import Process
from threading import Thread def func(i):
return '我是任务%s'%i if __name__ == '__main__': # 多线程
t_list = []
t_start_time = time.time()
for i in range(10):
t = Thread(target=func,args=(i,))
t_list.append(t)
t.start() [tt.join() for tt in t_list]
t_end_time = time.time()
t_dif_time = t_end_time - t_start_time # 多进程
p_list = []
p_start_time = time.time()
for i in range(10):
p = Process(target=func,args=(i,))
p_list.append(p)
p.start() [pp.join() for pp in p_list]
p_end_time = time.time()
p_dif_time = p_end_time - p_start_time
# 结果受cpu影响 print('多线程耗时:',t_dif_time)
print('多进程耗时:',p_dif_time)
print('主线程结束') '''
多线程耗时: 0.0020008087158203125
多进程耗时: 0.4188823699951172
'''
多线程和多进程效率对比
线程之间共享进程资源(全局变量在多个线程之间共享),但也会导致数据不但全问题
import time
from threading import Thread num = 100 def func():
global num
tep = num # tep替换 模拟多步操作
time.sleep(0.001) # 模拟延迟
tep -= 1
num = tep if __name__ == '__main__': t_list = []
for i in range(100):
t = Thread(target=func,)
t_list.append(t)
t.start() [tt.join() for tt in t_list] print('主线程的num',num) # 打印出不是100可知数据是共享的 # 理论上应该是0,但多线程是并发执行的,会出现上一个线程还在运算中时,下一个线程并未等待它返回值
# 也拿了原来的值进来运算,所以打印出了91,92,93不等,可知多线程数据是不安全的
'''
主线程的num 92
'''
验证多线程之间数据共享 数据不安全问题
加锁解决多线程数据不安全问题
import time
from threading import Thread,Lock num = 100
def func(lock,i):
global num
lock.acquire() # 加锁 tep = num
time.sleep(0.001) # 模拟延迟
tep -= 1
num = tep lock.release() # 释放 if __name__ == '__main__':
t_list = []
lock = Lock()
for i in range(100):
t = Thread(target=func,args=(lock,i))
t_list.append(t)
t.start() [tt.join() for tt in t_list]
print('主线程num',num) '''
主线程num 0
'''
Lock
信号量Semaphore
import time,random
from threading import Thread,Semaphore def func(i,s):
s.acquire()
print('%s张烧饼'%i)
time.sleep(random.randint(1,3))
s.release()
# 出来一个进去一个 始终6个 最后不足6个就都进来了 if __name__ == '__main__':
s = Semaphore(6) # 与Lock类似,不过可限制最大连接数,如这里同时只有6个线程可以获得semaphore
for i in range(28):
t = Thread(target=func,args=(i,s,))
t.start()
Semaphore
5.死锁和递归锁
死锁现象:有多个锁时,双方互相等待对方释放对方手里拿到的那个锁导致死锁
import time
from threading import Thread,Lock def func1(lock_A,lock_B):
lock_A.acquire()
print('张全蛋拿到了A锁')
time.sleep(0.5)
lock_B.acquire()
print('张全蛋拿到了B锁')
lock_B.release()
lock_A.release() def func2(lock_A,lock_B):
lock_B.acquire()
print('赵二狗拿到了B锁')
lock_A.acquire()
print('赵二狗拿到了A锁')
lock_A.release()
lock_B.release() if __name__ == '__main__': lock_A = Lock()
lock_B = Lock()
t1 = Thread(target=func1,args=(lock_A,lock_B,))
t2 = Thread(target=func2,args=(lock_A,lock_B,))
t1.start()
t2.start()
死锁现象
递归锁:RLock
RLock管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
# 递归锁解决死锁现象
import time
from threading import Thread,Lock,RLock def func1(lock_A,lock_B):
lock_A.acquire()
print('张全蛋拿到了A锁')
time.sleep(0.5)
lock_B.acquire()
print('张全蛋拿到了B锁')
lock_B.release()
lock_A.release() def func2(lock_A,lock_B):
lock_B.acquire()
print('赵二狗拿到了B锁')
lock_A.acquire()
print('赵二狗拿到了A锁')
lock_A.release()
lock_B.release() if __name__ == '__main__': # lock_A = Lock()
# lock_B = Lock()
lock_A = lock_B = RLock()
t1 = Thread(target=func1,args=(lock_A,lock_B,))
t2 = Thread(target=func2,args=(lock_A,lock_B,))
t1.start()
t2.start()
递归锁解决死锁现象
第三十三天- 线程创建、join、守护线程、死锁的更多相关文章
- 线程 Thread Runnable 守护线程 join MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...
- Java多线程(十)——线程优先级和守护线程
一.线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon( ...
- Java 多线程基础(十一)线程优先级和守护线程
Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...
- java的守护线程与非守护线程
最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) ,(PS:以 ...
- Java中的守护线程和非守护线程(转载)
<什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...
- Java - 线程优先级和守护线程
Java多线程系列--“基础篇”10之 线程优先级和守护线程 概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注 ...
- java 多线程之 线程优先级和守护线程
线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5."高优先级线程"会优先于"低优先级线程"执行. java 中有两种线程:用户线程和 ...
- [Java基础] java的守护线程与非守护线程
最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) ,(PS:以 ...
随机推荐
- css3的帧动画
概述 前几天刚好看到一个用了CSS3帧动画的页面,对它非常感兴趣,就研究了一下,记录在下面,供以后开发时参考,相信对其他人也有用. PS:以后别人问我用过什么CSS3属性的时候,我也可以不用说常见的a ...
- 分布式管理GIT命令总结(转载)
GIT是个了不起但却复杂的源代码管理系统.它能支持复杂的任务,却因此经常被认为太过复杂而不适用于简单的日常工作.让我们诚实一记吧:Git是复杂的,我们不要装作它不是.但我仍然会试图教会你用(我的)基本 ...
- vscode 学习笔记 —— 调试 (以 node 为例)
一.建立配置文件 1.选择你的项目 2.选择你项目的语言 3.当前项目路径下生成 .vscode/launch.json { // Use IntelliSense to learn about po ...
- 在express3里用ejs模版引擎时,如何使其支持'.html'后缀
①express 默认jade模板,改为ejs模板,需执行以下命令: express -e --ejs ②在app.js中,将 app.set('view engine', 'jade'); 替换为 ...
- python之ETL数据清洗案例源代码
#python语言 import pandas as pd import time data = pd.read_excel('ETL_数据清洗挑战.xlsx','测试数据',dtype=str)#读 ...
- @transactional作用和事务
今天在博客园看到有发布spring的注解,留意到@transactional这个注解.立马就百度.学习了 使用这个注解的类或者方法表示该类里面的所有方法或者这个方法的事务由spring处理,来保证事务 ...
- This Gradle plugin requires Studio 3.0 minimum
从github上下载的项目遇到一个问题:Error:This Gradle plugin requires Studio 3.0 minimum 意思就是说studio版本不高,导入的项目的版本是3. ...
- C#基础篇九OOP属性结构枚举
1.设计一个Ticket类,有一个距离属性(本属性只读,在构造方法中赋值),不能为负数,有一个价格属性,价格属性只读,并且根据距离计算价格(1元/公里):-----------0-100公里 票价不打 ...
- ES6基础教程一 学习笔记
一.变量的声明 1.var 声明全局变量 在ES6中var用来声明全局变量. 2.let 声明局部变量 3.const 声明常量 二.变量的解构赋值 //1.数组赋值 let [a,b,c]=[1,2 ...
- 一次完整的HTTP接口请求过程及针对优化
客户端发起http请求,基本的经历过程如下: 域名解析 -> TCP三次握手 -> 建立TCP连接后发起HTTP请求 -> Nginx反向代理 -> 应用层 -> 服务层 ...