第三十三天- 线程创建、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:以 ...
随机推荐
- [原创]K8_C段旁注查询工具5.0 30款国外主流CMS识别+智能识别未知CMS
8_C段旁注查询工具V5.0 20161214作者:K8拉登哥哥 唯一QQ:396890445平台: Windows + .NET Framework 4.0 简介:K8_C段 提供4种方式查询子域名 ...
- mvc大对象json传输报错
public ActionResult GetLargeJsonResult() { return new ContentResult { Content = new JavaScriptSerial ...
- C# 多线程学习系列二
一.关于前台线程和后台线程 1.简介 CLR中线程分为两种类型,一种是前台线程.另一种是后台线程. 前台线程:应用程序的主线程.Thread构造的线程都默认为前台线程 后台线程:线程池线程都为后台线程 ...
- C++ STL基本容器的使用(vector、list、deque、map、stack、queue)
1.关联容器和顺序容器 C++中有两种类型的容器:顺序容器和关联容器,顺序容器主要有:vector.list.deque等.关联容器主要有map和set.如下图: 1.vector基本使用 #incl ...
- 微信正式开放内测“小程序”,不开发APP的日子真的来了?
关注,QQ群,微信应用号社区 511389428 微信正式开放内测“小程序”,不开发APP的日子真的来了? 明星公司 缪定纯 • 2016-09-22 09:05 讨论了很久的微信应用号终于来了,不过 ...
- 使用vue开发微信公众号下SPA站点的填坑之旅
原文发表于本人博客,点击进入使用vue开发微信公众号下SPA站点的填坑之旅 本文为我创业过程中,开发项目的填坑之旅.作为一个技术宅男,我的项目是做一个微信公众号,前后端全部自己搞定,不浪费国家一分钱^ ...
- Redis for Windows
要求 必备知识 熟悉基本编程环境搭建. 运行环境 windows 7(64位); redis64-2.8.17 下载地址 环境下载 什么是Redis redis是一个key-value存储系统.和Me ...
- zepto中的touch库与fastclick
1. touch库实现了什么和引入背景 click事件在移动端上会有 300ms 的延迟,同时因为需要 长按 , 双触击 等富交互,所以我们通常都会引入类似 zepto 这样的库.zepto 中tou ...
- freemark null处理
以下引用官方描述: 引用The FreeMarker template language doesn't know the Java language null at all. It doesn't ...
- 页面打印pdf格式文件
'<td><button type="button" class="btn btn-primary" data-loading-text=&q ...