我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python全栈之线程详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python全栈之线程详解

1. 线程的概念

1.1 Manager_进程通信


# ### Manager ( list 列表  ,  dict 字典 ) 进程之间共享数据
from multiprocessing import Process , Manager ,Lock
def mywork(data,lock):
	# 共享字典
	"""
	lock.acquire()
	data["count"] -= 10
	lock.release()
	"""
	# 共享列表
	data[0] += 1
if __name__ == "__main__":
	lst = []
	m = Manager()
	lock = Lock()
	# 多进程中的共享字典
	# data = m.dict(  {"count":5000}  )
	# print(data , type(data) )
	# 多进程中的共享列表
	data =  m.list( [100,200,300] )
	# print(data , type(data) )
	""""""
	# 进程数超过1000,处理该数据,死机(谨慎操作)
	for i in range(10):
		p = Process(target=mywork,args=(data,lock))
		p.start()
		lst.append(p)
	# 必须等待子进程所有计算完毕之后,再去打印该字典,否则报错;
	for i in lst:
		i.join()
	print(data)

1.2 线程的概念

线程概念:


#进程是资源分配的最小单位
#线程是计算机中调度的最小单位
#线程的缘起
资源分配需要分配内存空间,分配cpu:
分配的内存空间存放着临时要处理的数据等,比如要执行的代码,数据
而这些内存空间是有限的,不能无限分配
目前配置高的主机,5万个并发已是上限.线程概念应用而生.
#线程的特点
线程是比较轻量级,能干更多的活,一个进程中的所有线程资源是共享的.
一个进程至少有一个线程在工作

线程的缺陷:


#python中的线程可以并发,但是不能并行(同一个进程下的多个线程不能分开被多个cpu同时执行)
#原因:
   全局解释器锁(Cpython解释器特有) GIL锁:
   同一时间,一个进程下的多个线程只能被一个cpu执行,不能实现线程的并行操作   
   python是解释型语言,执行一句编译一句,而不是一次性全部编译成功,不能提前规划,都是临时调度
   容易造成cpu执行调度异常.所以加了一把锁叫GIL   	
#想要并行的解决办法:
    (1)用多进程间接实现线程的并行
    (2)换一个Pypy,Jpython解释器
#程序分为计算密集型和io密集型
	对于计算密集型程序会过度依赖cpu,但网页,爬虫,OA办公,这种io密集型的程序里,python绰绰有余

小结:


进程中的线程,同一时间只能有一个cup(单核来回切换进行处理线程)来执行,单核之间可以进程切换
工作,以避免一个单核持续工作,过热导致频率降低。(java可以在同一时间进行多核操作,也就是同步操作)
线程是执行调度的最小单位
一个进程包含多个线程,一个进程至少一个线程
线程在一个进程当中可以共享一份资源
线程的缺陷:不能并行(java可以)
一个程序,至少一个主进程和一个主线程

在这里插入图片描述

2. 线程的基本使用


# ### 线程 
"""
进程是资源分配的最小单元
线程是cpu执行调度的最小单元
"""
# (1) 一个进程里包含了多个线程,线程之间是异步并发
from threading import Thread
from multiprocessing import Process
import os , time , random
"""
def func(i):
	time.sleep(random.uniform(0.1,0.9))
	print("当前进程号:{}".format(os.getpid()) , i)
if __name__ == "__main__":
	for i in range(10):
		t = Thread(target=func,args=(i,))
		t.start()
print(os.getpid())
"""
# (2) 并发的多进程和多线程之间,多线程的速度更快
# 多线程速度
def func(i):
	print( "当前进程号:{} , 参数是{} ".format(os.getpid() , i)  )
"""
if __name__ == "__main__":
	lst = []
	startime = time.time()
	for i in range(10000):
		t = Thread(target=func,args=(i,))
		t.start()
		lst.append(t)
	# print(lst)
	for i in lst:
		i.join()
	endtime = time.time()
	print("运行的时间是{}".format(endtime - startime) ) # 运行的时间是1.8805944919586182
"""
# 多进程速度
"""
if __name__ == "__main__":
	lst = []
	startime = time.time()
	for i in range(10000):
		p = Process(target=func,args=(i,))
		p.start()
		lst.append(p)
	# print(lst)
	for i in lst:
		i.join()
	endtime = time.time()
	print("运行的时间是{}".format(endtime - startime) ) # 运行的时间是101.68004035949707
"""
# (3) 多线程之间,数据共享
num = 100
lst = []
def func():
	global num
	num -= 1
for i in range(100):
	t = Thread(target=func)
	t.start()
	lst.append(t)
for i in lst:
	i.join()
print(num)

在这里插入图片描述

小提示: 一个线程对变量进行操作的时候,其他的线程就不能在对这个变量进行操作。这个时候用锁把线程锁住。

3. 自定义线程_守护线程

3.1 自定义线程


# ### 用类定义线程
from threading import Thread
import os,time
# (1)必须继承父类Thread,来自定义线程类
"""
class MyThread(Thread):
	def __init__(self,name):
		# 手动调用父类的构造方法
		super().__init__()
		# 自定义当前类需要传递的参数
		self.name = name
	def run(self):
		print(  "当前进程号{},name={}".format(os.getpid() , self.name)  )
if __name__ == "__main__":
	t = MyThread("我是线程")
	t.start()
	print( "当前进程号{}".format(os.getpid()) )
"""
# ### 线程中的相关属性
"""
# 线程.is_alive()    检测线程是否仍然存在
# 线程.setName()     设置线程名字
# 线程.getName()     获取线程名字
# 1.currentThread().ident 查看线程id号 
# 2.enumerate()        返回目前正在运行的线程列表
# 3.activeCount()      返回目前正在运行的线程数量
"""
"""
def func():
	time.sleep(1)
if __name__ == "__main__":
	t = Thread(target=func)
	t.start()
	# 检测线程是否仍然存在
	print( t.is_alive() )
	# 线程.getName()     获取线程名字
	print(t.getName())
	# 设置线程名字
	t.setName("抓API接口")
	print(t.getName())
"""
from threading import currentThread
from threading import enumerate
from threading import activeCount
def func():
	time.sleep(0.1)
	print("当前子线程号id是{},进程号{}".format( currentThread().ident ,os.getpid()) )
if __name__ == "__main__":
	t = Thread(target=func)
	t.start()
	print("当前主线程号id是{},进程号{}".format( currentThread().ident ,os.getpid()) )
	for i in range(5):
		t = Thread(target=func)
		t.start()
	# 返回目前正在运行的线程列表
	lst = enumerate()
	print(lst,len(lst))
	# 返回目前正在运行的线程数量 (了解)
	print(activeCount())

3.2 守护线程


# ### 守护线程 : 等待所有线程全部执行完毕之后,自己在终止程序,守护所有线程
from threading import Thread
import time
def func1():
	while True:
		time.sleep(1)		
		print("我是函数func1")
def func2():
	print("我是func2  start ... ")
	time.sleep(3)
	print("我是func2  end ... ")
def func3():
	print("我是func3 start ... ")
	time.sleep(6)	
	print("我是func3  end ... ")
if __name__ == "__main__":
	t = Thread(target=func1)
	t2 = Thread(target=func2)
	t3 = Thread(target=func3)
	# 设置守护线程 (启动前设置)
	t.setDaemon(True)
	t.start()
	t2.start()
	t3.start()
	print("主线程执行结束.... ")

4. 线程安全问题

4.1 线程安全问题


# ### 线程中的数据安全问题
from threading import  Thread  , Lock
import time
n = 0
def func1(lock):
	global n
	lock.acquire() 
	for i in range(1000000):		
		n += 1
	lock.release()
def func2(lock):
	global n
	# with语法可以简化上锁+解锁的操作,自动完成
	with lock:
		for i in range(1000000):
			n -= 1
if __name__ == "__main__":
	lst = []
	lock = Lock()
	start = time.time()
	for i in range(10):
		t1 = Thread(target=func1 ,args=(lock,) )
		t1.start()
		t2 = Thread(target=func2 ,args=(lock,) )
		t2.start()
		lst.append(t1)
		lst.append(t2)
	for i in lst:
		i.join()
	# print(lst,len(lst))
	end = time.time()
	print("主线程执行结束... 当前n结果为{} ,用时{}".format(n , end-start))

4.2 Semaphore_信号量


# ### 信号量 Semaphore (线程)
"""同一时间对多个线程上多把锁"""
from threading import Thread,Semaphore
import time , random
def func(i,sem):
	time.sleep(random.uniform(0.1,0.7))
	# with语法自动实现上锁 + 解锁
	with sem:		
		print("我在电影院拉屎 .... 我是{}号".format(i))
if __name__ == "__main__":
	sem = Semaphore(5)
	for i in range(30):
		Thread(target=func,args=(i,sem)).start()
	print(1)
"""
	创建线程是异步的,
	上锁的过程会导致程序变成同步;
"""		

5. 死锁_互斥锁_递归锁


加一把锁,就对应解一把锁.形成互斥锁.
从语法上来说,锁可以互相嵌套,但不要使用,
不要因为逻辑问题让上锁分成两次.导致死锁
递归锁用于解决死锁,但只是一种应急的处理办法

# ### 互斥锁 死锁 递归锁
from threading import Thread , Lock , RLock
import time
# (1) 语法上的死锁
"""语法上的死锁: 是连续上锁不解锁"""
"""
lock = Lock()
lock.acquire()
# lock.acquire() error
print("代码执行中 ... 1")
lock.release()
lock.release()
"""
"""是两把完全不同的锁"""
lock1 = Lock()
lock2 = Lock()
lock1.acquire()
lock2.acquire()
print("代码执行中 ... 2")
lock2.release()
lock1.release()
# (2) 逻辑上的死锁
""""""
noodles_lock = Lock()
kuaizi_lock = Lock()
def eat1(name):
	noodles_lock.acquire()
	print("{}抢到面条了 ... ".format(name))
	kuaizi_lock.acquire()
	print("{}抢到筷子了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)
	kuaizi_lock.release()
	print("{}吃完了,满意的放下了筷子".format(name))
	noodles_lock.release()
	print("{}吃完了,满意的放下了面条".format(name))
def eat2(name):
	kuaizi_lock.acquire()
	print("{}抢到筷子了 ... ".format(name))
	noodles_lock.acquire()
	print("{}抢到面条了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)	
	noodles_lock.release()
	print("{}吃完了,满意的放下了面条".format(name))
	# kuaizi_lock.release()
	print("{}吃完了,满意的放下了筷子".format(name))
if __name__ == "__main__":
	lst1 = ["康裕康","张宇"]
	lst2 = ["张保张","赵沈阳"]
	for name in lst1:
		Thread(target=eat1,args=(name,)).start()
	for name in lst2:
		Thread(target=eat2,args=(name,)).start()
# (3) 使用递归锁
"""
	递归锁的提出专门用来解决死锁现象
	用于快速解决线上项目死锁问题
	即使连续上锁,使用递归锁后也形同虚设,因为递归锁的作用在于解锁;
"""
"""
# 基本语法
rlock = RLock()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
print("代码执行中 ... 3")
rlock.release()
rlock.release()
rlock.release()
rlock.release()
"""
"""
noodles_lock = Lock()
kuaizi_lock = Lock()
# 让noodles_lock和kuaizi_lock 都等于递归锁
noodles_lock = kuaizi_lock = RLock()
def eat1(name):
	noodles_lock.acquire()
	print("{}抢到面条了 ... ".format(name))
	kuaizi_lock.acquire()
	print("{}抢到筷子了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)
	kuaizi_lock.release()
	print("{}吃完了,满意的放下了筷子".format(name))
	noodles_lock.release()
	print("{}吃完了,满意的放下了面条".format(name))
def eat2(name):
	kuaizi_lock.acquire()
	print("{}抢到筷子了 ... ".format(name))
	noodles_lock.acquire()
	print("{}抢到面条了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)	
	noodles_lock.release()
	print("{}吃完了,满意的放下了筷子".format(name))
	kuaizi_lock.release()
	print("{}吃完了,满意的放下了筷子".format(name))
if __name__ == "__main__":
	lst1 = ["康裕康","张宇"]
	lst2 = ["张保张","赵沈阳"]
	for name in lst1:
		Thread(target=eat1,args=(name,)).start()
	for name in lst2:
		Thread(target=eat2,args=(name,)).start()
"""
# (4) 尽量使用一把锁解决问题,(少用锁嵌套,容易逻辑死锁)
"""
lock = Lock()
def eat1(name):
	lock.acquire()
	print("{}抢到面条了 ... ".format(name))
	print("{}抢到筷子了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)	
	print("{}吃完了,满意的放下了筷子".format(name))	
	print("{}吃完了,满意的放下了面条".format(name))
	lock.release()
def eat2(name):
	lock.acquire()
	print("{}抢到筷子了 ... ".format(name))
	print("{}抢到面条了 ... ".format(name))
	print("开始享受香菇青菜面 ... ")
	time.sleep(0.5)	
	print("{}吃完了,满意的放下了筷子".format(name))
	print("{}吃完了,满意的放下了筷子".format(name))
	lock.release()
if __name__ == "__main__":
	lst1 = ["康裕康","张宇"]
	lst2 = ["张保张","赵沈阳"]
	for name in lst1:
		Thread(target=eat1,args=(name,)).start()
	for name in lst2:
		Thread(target=eat2,args=(name,)).start()
"""

6. 线程事件


# ### 事件 Event
from threading import Thread , Event
import time,random
"""
wait   : 动态加阻塞 (True => 放行  False => 阻塞)
is_set : 获取内部成员属性值是True 还是 False
set    : 把False -> True
clear  : 把True  -> False
"""
# (1) 基本语法
"""
e = Event()
print(e.is_set())
e.set()
print(e.is_set())
e.wait()
e.clear()
# 最多阻塞三秒,放行
e.wait(3)
print("代码执行中 ... ")
"""
# (2) 模拟连接远程数据库
"""最多连接三次,如果三次都连接不上,直接报错."""
def check(e):	
	print("目前正在检测您的账号和密码 .... ")
	# 模拟延迟的场景
	time.sleep(random.randrange(1,7)) # 1 ~ 6
	# 把成员属性值从False -> True
	e.set()
def connect(e):
	sign = False
	for i in range(1,4):
		e.wait(1)
		if e.is_set():
			print("数据库连接成功 ... ")
			sign = True
			break
		else:
			print("尝试连接数据库第{}次失败了...".format(i))
	# 三次都不成功,报错
	if sign == False:
		# 主动抛出异常  超时错误
		raise TimeoutError
# if __name__ == "__main__":
e = Event()
t1 = Thread(target=check,args=(e,))
t1.start()
t2 = Thread(target=connect,args=(e,))
t2.start()

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python全栈之线程详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详解Java线程堆栈

写在前面: 线程堆栈应该是多线程类应用程序非功能问题定位的最有效手段,可以说是杀手锏。线程堆栈最擅长与分析如下类型问题:系统无缘无故CPU过高。系统挂起,无响应。系统运行越来越慢。性能瓶颈(如无法充分利用CPU等)线程死锁、死循环,饿死等。
2023-05-30

python 全栈之路

目录 Python 全栈之路 一. Python 1. Python基础知识部分 2. Python -函数 3. Python - 模块
2023-01-30

Python全栈之路系列之Python

The Python interpreter has a number of functions and types built into it that are always available. They are listed here
2023-01-31

Python全栈开发之网络编程

No.1 TCP/IP早期的计算机网络,都是由厂商规定自己的通信协议,互不兼容,为了把全世界不同类型的计算机连接起来,就必须规定一套全球通用的协议,所以就出现了TCP/IPNo.2 Socket简介要解决怎么标识一个进制,在一台电脑上可以同
2023-01-31

Python全栈开发之并发编程

No.1 线程什么是多任务就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行并发和并行并发是指任务数多余cpu核数,通过操作系统的各种任务
2023-01-31

Python全栈之jQuery笔记

jQuery runnoob网址:http://www.runoob.com/jquery/jquery-tutorial.htmljQuery API手册: http://www.runoob.com/manual/jquery/jQue
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录