• Python线程详解


    一、 线程理论

    		进程是资源单位
    			进程相当于工厂的车间 进程负责给内部的线程提供相应的资源
    		线程是执行单位
    			线程相当于车间里面的流水线 线程负责执行真正的功能 
    			多个线程就多个流水线都是在进程的资源空间内
    		线程的特征:
    			1.一个进程至少有一个线程(没有进程哪来的线程 程序(客户端)没有运行什么都没有)
    			2.多进程与多线程的区别
    				多进程	需要申请内存空间 需要拷贝全部代码 资源消耗大	数据间不能共享
    				多线程	不需要申请内存空间 也不需要拷贝全部代码 资源消耗小 数据间可以共享
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    二、 创建线程的两种方式

    		开设线程不需要完整拷贝代码 所以无论什么系统都不会出现反复操作的情况 
    		也不需要在启动脚本中执行 但是为了兼容性和统一性 习惯在启动脚本中编写
    
    • 1
    • 2
    	第一种方式
    		from threading import Thread
    		import time				# 导入线程模块
    		
    		def task(name):			# 设置函数
    		    print(f'{name}正在运行')
    		    time.sleep(3)		# 休眠三秒
    		    print(f'{name}运行结束')
    		
    		if __name__ == '__main__':		# 设置运行脚本 兼容性提升 
    		    t = Thread(target=task, args=('LebronJames',))
    		    t.start()
    		    print('主线程')
    	
    	第二种方式
    		rom threading import Thread
    		import time 
    		
    		class MyThread(Thread):
    		    def __init__(self, name):
    		        super().__init__()
    		        self.name = name
    		
    		    def run(self):
    		        print(f'{self.name}正在运行')
    		        time.sleep(3)
    		        print(f'{self.name}运行结束')
    		
    		obj = MyThread('LebronJames')
    		obj.start()
    		print('主线程')
    
    		'''两个输出结果: LebronJames正在运行 主线程 LebronJames运行结束!!!'''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    三、 多线程实现TCP服务端并发

    		比多进程更加简单方便 消耗的资源更少
    		
    		Server:
    				import socket
    				from threading import Thread		# 导入模块
    				
    				server = socket.socket()
    				server.bind(('127.0.0.1', 8080))
    				server.listen(5)					# 设置端口 
    				
    				def talk(sock):		# 设置一个函数 接收数据 发送数据
    				    while True:
    				        data = sock.recv(1024)		
    				        print(data.decode('utf8'))
    				        sock.send(data.upper())
    				
    				while True:
    				    sock, addr = server.accept()		
    				    p = Thread(target=talk, args=(sock,))	 # 开设进程去完成数据交互
    				    p.start()
    
    		Clinet:
    				import socket
    				
    				client = socket.socket()
    				client.connect(('127.0.0.1', 8080))			# 设置固定的地址
    				
    				while True:
    				    client.send(b'hello baby')				# 发送数据
    				    data = client.recv(1024)
    				    print(data.decode('utf8'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    四、 Join方法

    		主线程等到子线程运行结束之后再运行(跟主线程一个道理)
    		
    		from threading import Thread
    		import time
    		
    		def task():
    		    print('正在执行')
    		    time.sleep(3)
    		    print('运行结束')
    		
    		t = Thread(target=task)
    		t.start()
    		t.join()
    		print('主线程')			# 输出结果 : 正在执行 运行结束 主线程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    五、 同一个进程下线程数据共享

    		from threading import Thread
    
    		money = 1000
    		
    		def func():
    		    global money			# 同一个进程下 线程之间数据共享 
    		    money = 666
    		
    		t = Thread(target=func)
    		t.start()					
    		t.join()  # 确保线程运行完毕 再查找money 结果更具有说服性
    		print(money)			# 输出结果: 666
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    六、 线程对象相关方法

    		1. 进程号
    			同一个进程下开设的多个线程拥有相同的进程号
    		2.线程名
    			需要使用到模块 from threading import Thread, current_thread
    			current_thread().name 
    			主:MainThread	子:Thread-N
    		3. 进程下的线程数 模块 active_count
    			active_count()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    		from threading import Thread, current_thread, active_count
    		import os
    		
    		money = 1000
    		
    		def func():
    		    global money
    		    money = 666
    		    print('子线程名', current_thread())
    		
    		t = Thread(target=func)
    		t.start()
    		t.join()  # 确保线程运行完毕 再查找money 结果更具有说服性
    		
    		print('子进程', os.getpid())
    		print('进程下的线程数',active_count())
    
    		输出结果:
    			子线程名 <Thread(Thread-1, started 13071642624)>
    			子进程 3233
    			进程下的线程数 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    七、 守护线程

    		守护线程伴随着被守护的线程的结束而结束
    		进程下所有的守护线程 主线程(主进程)结束 所有线程结束全部直接结束
    		进程下所有的非守护线程结束 主线程(主进程)才能真正结束!!!(没有被守护的结束了主线程才结束)
    
    • 1
    • 2
    • 3
    		from threading import Thread
    		import time
    		
    		def task():
    		    print('子线程运行task函数')
    		    time.sleep(3)
    		    print('子线程运行task结束')
    		
    		t = Thread(target=task)
    		t.daemon = True		# 伴随主线程 主线程结束子进程也结束
    		t.start()
    		# t.daemon = True	# 不能放在start下面 否则报错!
    		print('主线程')
    
    		输出结果 : 子线程运行task函数 主线程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    八、 GIL全局解释器锁

    		储备知识:
    			1.python解释器也是由编程语言写出来的
    				Cpython 用C写出来的	Jpython 用Java写出来的 Pypython 用python写出来的
    			2.GIL的研究是Cpython解释器的特点 不是python语言的特点
    			3.GIL本质也是一把互斥锁
    			4.GIL的存在使得同一个进程下的多个线程无法同时执行(关键)
    				言外之意:单进程下的多线程无法利用多核优势 效率低!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    		误解:
    			1.python的多线程就是垃圾 利用不到多核优势
    				python的多线程确实无法使用多核优势 但是在IO密集型的任务下是有用的
    			2.既然有GIL 那么以后我们写代码都不需要加互斥锁
    				不对 GIL只确保解释器层面数据不会错乱(垃圾回收机制)
    				针对程序中自己的数据应该自己加锁处理
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注 谢谢支持!

  • 相关阅读:
    高新技术企业领域划分
    code编译时报错undefined reference to ...
    花咲の姫君(異時層ツキハ) / 花咲(异时层妖刀)
    深入理解ThreadLocal及其变种
    k8s教程(13)-pod定向调度
    redisson使用过程常见问题汇总
    Mybatis注解开发---增删改查
    MySQL 经验集总结(更新ing)
    Kubeadm部署Kubernetes Containerd集群
    JavaScript操作DOM元素的一些基础方法与属性
  • 原文地址:https://blog.csdn.net/MeiJin_/article/details/126272875