09-19-周五_14-48-32

This commit is contained in:
2025-09-19 14:48:32 +08:00
parent 66148187d0
commit ef0ed27b9e
2 changed files with 25 additions and 47 deletions

View File

@@ -31,7 +31,7 @@
### 使用线程的实际场景
开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
开启一个软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
### 内存中的线程
@@ -50,9 +50,9 @@
### 全局解释器锁GIL
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
  对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
  在多线程环境中Python 虚拟机按以下方式执行:
在多线程环境中Python 虚拟机按以下方式执行:
1. 设置 GIL
@@ -65,7 +65,8 @@ Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Pyt
5. 解锁 GIL
6. 再次重复以上所有步骤。
在调用外部代码(如 C/C++扩展函数)的时候GIL将会被锁定直到这个函数结束为止(由于在这期间没有Python的字节码被运行所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。
在调用外部代码(如 C/C++扩展函数)的时候GIL将会被锁定直到这个函数结束为止(由于在这期间没有Python的字节码被运行所以不会做线程切换)编写扩展的程序可以主动解锁GIL。
### python线程模块的选择
@@ -87,7 +88,7 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t=Thread(target=sayhi,args=('张三',))
t.start()
print('主线程')
```
@@ -107,7 +108,7 @@ class Sayhi(Thread):
if __name__ == '__main__':
t = Sayhi('aaron')
t = Sayhi('张三')
t.start()
print('主线程')
```
@@ -256,7 +257,7 @@ import os
def work():
import time
time.sleep(3)
print(threading.current_thread().getName())
print(threading.current_thread().name)
if __name__ == '__main__':
@@ -264,7 +265,7 @@ if __name__ == '__main__':
t=Thread(target=work)
t.start()
print(threading.current_thread().getName())
print(threading.current_thread().name)
print(threading.current_thread()) #主线程
print(threading.enumerate()) #连同主线程在内有两个运行的线程
print(threading.active_count())
@@ -281,7 +282,7 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t=Thread(target=sayhi,args=('张三',))
t.start()
t.join()
print('主线程')
@@ -305,8 +306,8 @@ def sayhi(name):
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('aaron',))
t.setDaemon(True) #必须在t.start()之前设置
t=Thread(target=sayhi,args=('张三',))
t.daemon = True #必须在t.start()之前设置
t.start()
print('主线程')
@@ -433,8 +434,7 @@ from threading import current_thread,Thread,Lock
import os,time
def task():
#未加锁的代码并发运行
time.sleep(3)
print('%s start to run' %current_thread().getName())
print('%s start to run' %current_thread().name)
global n
#加锁的代码串行运行
lock.acquire()
@@ -459,34 +459,10 @@ if __name__ == '__main__':
```
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
没错:在start之后立刻使用join,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
```python
from threading import current_thread,Thread,Lock
import os,time
def task():
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
temp=n
time.sleep(0.5)
n=temp-1
if __name__ == '__main__':
n=100
lock=Lock()
start_time=time.time()
for i in range(100):
t=Thread(target=task)
t.start()
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n))
```
### 死锁与递归锁
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**