第三十三天- 线程创建、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:以 ...
 
随机推荐
- 在centos使用redis几个坑
			
问题来源 最近公司的平台需要做一些分布式的规划,其中会话我们打算用redis来存储,因为之前也有了解过redis,但都是在windows上使用,为了发挥redis的优势,这次我们打算直接在Linux上 ...
 - PowerDesigner生成OOM时类名属性名转换
			
Examples Script 1: Convert a name into a class code (JAVA naming convention)转换类名 .foreach_part(%Name ...
 - javaScript中BOM
			
BOM是browser object model的缩写,简称浏览器对象模型 主要处理浏览器窗口(window)和框架(iframe),简述了与浏览器进行交互的方法和接口, 可以对浏览器窗口进行访问和操 ...
 - Go指南练习 rot13Reader
			
题目: 练习:rot13Reader 有种常见的模式是一个 io.Reader 包装另一个 io.Reader,然后通过某种方式修改其数据流. 例如,gzip.NewReader 函数接受一个 io. ...
 - JavaScript -- Window-Interval
			
-----031-Window-Interval.html----- <!DOCTYPE html> <html> <head> <meta http-equ ...
 - mysql 删除单表内多个字段重复的数据
			
mysql 删除单表内多个字段重复的数据 DELETE from lot_log_payflow WHERE (pay_no,sub_flow_type) in () s1) AND id ) s2) ...
 - [Python]可变类型,默认参数与学弟的困惑
			
一.学弟的困惑 十天前一个夜阑人静.月明星稀的夜晚,我和我的朋友们正在学校东门的小餐馆里吃着方圆3里内最美味的牛蛙,唱着最好听的歌儿,畅聊人生的意义.突然,我的手机一震,气氛瞬间就安静下来,看着牛蛙碗 ...
 - es-03-DSL的简单使用
			
以下操作在kibana中进行, 如果在linux的shell中, 请使用 curl -Xget 'http://node1:9200/index/type/id' -d '{ ... }' 的形式, ...
 - centos 修改时区
			
# date 2014年 07月 22日 星期二 :: EDT # cat /etc/sysconfig/clock -------------------------- ZONE="Ame ...
 - 使用ssh-keygen生成ssh公钥和私钥
			
默认是在用户目录下: windows一般为 c:\User\username\.ssh下 linux一般为 /home/username/.ssh 生成的命令如下: ssh-keygen -t rsa ...