09-19-周五_14-48-32
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
### 使用线程的实际场景
|
### 使用线程的实际场景
|
||||||
|
|
||||||
开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
|
开启一个软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。
|
||||||
|
|
||||||
### 内存中的线程
|
### 内存中的线程
|
||||||
|
|
||||||
@@ -50,9 +50,9 @@
|
|||||||
### 全局解释器锁GIL
|
### 全局解释器锁GIL
|
||||||
|
|
||||||
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
|
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
|
||||||
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
|
对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
|
||||||
|
|
||||||
在多线程环境中,Python 虚拟机按以下方式执行:
|
在多线程环境中,Python 虚拟机按以下方式执行:
|
||||||
|
|
||||||
1. 设置 GIL;
|
1. 设置 GIL;
|
||||||
|
|
||||||
@@ -65,7 +65,8 @@ Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Pyt
|
|||||||
5. 解锁 GIL;
|
5. 解锁 GIL;
|
||||||
|
|
||||||
6. 再次重复以上所有步骤。
|
6. 再次重复以上所有步骤。
|
||||||
在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。
|
|
||||||
|
在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序可以主动解锁GIL。
|
||||||
|
|
||||||
### python线程模块的选择
|
### python线程模块的选择
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.start()
|
t.start()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
```
|
```
|
||||||
@@ -107,7 +108,7 @@ class Sayhi(Thread):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t = Sayhi('aaron')
|
t = Sayhi('张三')
|
||||||
t.start()
|
t.start()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
```
|
```
|
||||||
@@ -256,7 +257,7 @@ import os
|
|||||||
def work():
|
def work():
|
||||||
import time
|
import time
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -264,7 +265,7 @@ if __name__ == '__main__':
|
|||||||
t=Thread(target=work)
|
t=Thread(target=work)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print(threading.current_thread()) #主线程
|
print(threading.current_thread()) #主线程
|
||||||
print(threading.enumerate()) #连同主线程在内有两个运行的线程
|
print(threading.enumerate()) #连同主线程在内有两个运行的线程
|
||||||
print(threading.active_count())
|
print(threading.active_count())
|
||||||
@@ -281,7 +282,7 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.start()
|
t.start()
|
||||||
t.join()
|
t.join()
|
||||||
print('主线程')
|
print('主线程')
|
||||||
@@ -305,8 +306,8 @@ def sayhi(name):
|
|||||||
print('%s say hello' %name)
|
print('%s say hello' %name)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
t=Thread(target=sayhi,args=('aaron',))
|
t=Thread(target=sayhi,args=('张三',))
|
||||||
t.setDaemon(True) #必须在t.start()之前设置
|
t.daemon = True #必须在t.start()之前设置
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
print('主线程')
|
print('主线程')
|
||||||
@@ -433,8 +434,7 @@ from threading import current_thread,Thread,Lock
|
|||||||
import os,time
|
import os,time
|
||||||
def task():
|
def task():
|
||||||
#未加锁的代码并发运行
|
#未加锁的代码并发运行
|
||||||
time.sleep(3)
|
print('%s start to run' %current_thread().name)
|
||||||
print('%s start to run' %current_thread().getName())
|
|
||||||
global n
|
global n
|
||||||
#加锁的代码串行运行
|
#加锁的代码串行运行
|
||||||
lock.acquire()
|
lock.acquire()
|
||||||
@@ -459,34 +459,10 @@ if __name__ == '__main__':
|
|||||||
```
|
```
|
||||||
|
|
||||||
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
|
有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊
|
||||||
没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
|
没错:在start之后立刻使用join,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是
|
||||||
start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的
|
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))
|
|
||||||
```
|
|
||||||
|
|
||||||
### 死锁与递归锁
|
### 死锁与递归锁
|
||||||
|
|
||||||
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**
|
两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程**
|
||||||
|
@@ -127,7 +127,7 @@ from greenlet import greenlet
|
|||||||
|
|
||||||
def eat(name):
|
def eat(name):
|
||||||
print('%s eat 1' %name)
|
print('%s eat 1' %name)
|
||||||
g2.switch('aaron')
|
g2.switch('张三')
|
||||||
print('%s eat 2' %name)
|
print('%s eat 2' %name)
|
||||||
g2.switch()
|
g2.switch()
|
||||||
def play(name):
|
def play(name):
|
||||||
@@ -138,7 +138,7 @@ def play(name):
|
|||||||
g1=greenlet(eat)
|
g1=greenlet(eat)
|
||||||
g2=greenlet(play)
|
g2=greenlet(play)
|
||||||
|
|
||||||
g1.switch('aaron') # 可以在第一次switch时传入参数,以后都不需要
|
g1.switch('张三') # 可以在第一次switch时传入参数,以后都不需要
|
||||||
```
|
```
|
||||||
|
|
||||||
单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度
|
单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度
|
||||||
@@ -224,8 +224,8 @@ def play(name):
|
|||||||
print('%s play 2' %name)
|
print('%s play 2' %name)
|
||||||
|
|
||||||
|
|
||||||
g1=gevent.spawn(eat,'aaron')
|
g1=gevent.spawn(eat,'张三')
|
||||||
g2=gevent.spawn(play,name='aaron')
|
g2=gevent.spawn(play,name='张三')
|
||||||
g1.join()
|
g1.join()
|
||||||
g2.join()
|
g2.join()
|
||||||
#或者gevent.joinall([g1,g2])
|
#或者gevent.joinall([g1,g2])
|
||||||
@@ -259,7 +259,7 @@ gevent.joinall([g1,g2])
|
|||||||
print('主')
|
print('主')
|
||||||
```
|
```
|
||||||
|
|
||||||
用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程
|
用threading.current_thread().name来查看每个g1和g2,查看的结果为DummyThread-n,即假线程
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from gevent import monkey;monkey.patch_all()
|
from gevent import monkey;monkey.patch_all()
|
||||||
@@ -267,13 +267,13 @@ import threading
|
|||||||
import gevent
|
import gevent
|
||||||
import time
|
import time
|
||||||
def eat():
|
def eat():
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print('eat food 1')
|
print('eat food 1')
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print('eat food 2')
|
print('eat food 2')
|
||||||
|
|
||||||
def play():
|
def play():
|
||||||
print(threading.current_thread().getName())
|
print(threading.current_thread().name)
|
||||||
print('play 1')
|
print('play 1')
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
print('play 2')
|
print('play 2')
|
||||||
@@ -372,6 +372,8 @@ def talk(conn,addr):
|
|||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
res=conn.recv(1024)
|
res=conn.recv(1024)
|
||||||
|
if len(res) == 0:
|
||||||
|
continue
|
||||||
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
|
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
|
||||||
conn.send(res.upper())
|
conn.send(res.upper())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -389,7 +391,7 @@ if __name__ == '__main__':
|
|||||||
from socket import *
|
from socket import *
|
||||||
|
|
||||||
client=socket(AF_INET,SOCK_STREAM)
|
client=socket(AF_INET,SOCK_STREAM)
|
||||||
client.connect(('127.0.0.1',8080))
|
client.connect(('127.0.0.1',8088))
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -414,7 +416,7 @@ def client(server_ip,port):
|
|||||||
|
|
||||||
count=0
|
count=0
|
||||||
while True:
|
while True:
|
||||||
c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8'))
|
c.send(('%s say hello %s' %(threading.current_thread().name,count)).encode('utf-8'))
|
||||||
msg=c.recv(1024)
|
msg=c.recv(1024)
|
||||||
print(msg.decode('utf-8'))
|
print(msg.decode('utf-8'))
|
||||||
count+=1
|
count+=1
|
||||||
|
Reference in New Issue
Block a user