디렉토리
동시 프로그래밍 요약 (2)
세마포어
- 세마포어는 실제로 잠금입니다.
- 동시에 뮤텍스 하나의 스레드 만 사용할 수 있도록하고, 세마포어는 다중 스레드를 할 수 있습니다. 세마포어가 인스턴스화 될 때, 동시 스레드의 수를 정의하는 매개 변수를 전달할 수
- 당신은 가이드가 필요
from threading import Semaphore
예 :
from threading import Semaphore, Lock
from threading import current_thread
from threading import Thread
import time
sm = Semaphore(5) #
mutex = Lock() #
def task():
# mutex.acquire()
sm.acquire()
print(f'{current_thread().name}执行任务')
time.sleep(1)
sm.release()
# mutex.release()
for line in range(20):
t = Thread(target=task)
t.start()
# 结果:
Thread-1执行任务
Thread-2执行任务
Thread-3执行任务
Thread-4执行任务
Thread-5执行任务
此处等待1秒 # 就是每个线程里的那个 time.sleep(1)
Thread-6执行任务
Thread-9执行任务
Thread-7执行任务
Thread-8执行任务
Thread-10执行任务
此处等待1秒
Thread-11执行任务
Thread-14执行任务
Thread-12执行任务
Thread-13执行任务
Thread-15执行任务
此处等待1秒
Thread-16执行任务
Thread-18执行任务
Thread-17执行任务
Thread-19执行任务
Thread-20执行任务
此处等待1秒
두 이벤트
1. 이벤트는 무엇입니까
- 그것은 스레딩하는 방법입니다. 스레드는 차단 및 차단 해제를 제어하는 데 사용됩니다.
사용이 무엇 2. 이벤트
- 스레드의 실행을 제어하는 데 사용, 스레드는 실행의 다른 스레드들에 의해 제어됩니다.
3. 이벤트 방법
wait
이러한 코드는 스레드가 존재하는 경우, 당신은 영구 차단 상태가됩니다 발생합니다.set
이러한 코드는 스레드가 존재하는 경우, 모든 만날wait
오픈. 준비 상태로 이러한 원래 스레드.
예 :
def light():
print('红灯亮...')
time.sleep(5)
# 应该开始发送信号,告诉其他线程准备执行
e.set() # 将car中的False ---> True
print('绿灯亮...')
def car(name):
print('正在等红灯....')
# 让所有汽车任务进入阻塞态
e.wait() # False
print(f'{name}正在加速漂移....')
# 让一个light线程任务 控制多个car线程任务
t = Thread(target=light)
t.start()
for line in range(10):
t = Thread(target=car, args=(f'童子军jason{line}号', ))
t.start()
셋째, 프로세스 스레드 풀 수영장
1. 프로세스 스레드 풀 수영장 무엇입니까
- 프로세스 풀 및 스레드 풀은 현재의 프로그램을 제어하는 데 사용되는 숫자 / 스레드를 생성하는 과정을 수 있습니다.
사용이 무엇 2. 프로세스 풀 및 스레드 풀
- 수가 하드웨어 프로세스 / 스레드에 의해 허용 범위가되도록 만든
3.
도서관 안내 :
from concurrent.futures import ProcessPoolExecutor
셀 프로세스 / 스레드 풀 오브젝트의 예는 :
pool = ThreadPoolExecutor(n)
n은 기입 시간으로부터 충전 할 수 있고, (N)의 충전 개구 CPU 번호를 기입하지 않고, 프로세스 / 쓰레드를 나타내는 것은 * 5 CPU의 개수를 제한하는 기본 제한을 프로세스 수, 기본 스레드 수를 나타낸다submit
주소 (즉, 함수 이름)의 함수에 매개 변수 전달, 비동기 작업을 제출하는 것입니다.submit(任务函数地址).add_done_callback(回调函数的地址)
. 작업이 값을 반환 할 때이 함수는 콜백 함수에 의해 받았을 때. 콜백 같은 형상 파라미터로서res
,res
하지 함수의 리턴 값의 작업. 하여res.result()
함수의 반환 값 작업을 얻을 수 있습니다.shutdown
결국 그것은 아래로 프로세스 / 스레드와 비슷한 코드를 실행, 스레드 풀 작업을 할 것입니다join
효과
예 :
# 任务函数没有返回值时*************************
def task():
print('线程任务开始了...')
time.sleep(3)
print('线程任务结束了...')
for line in range(5):
pool.submit(task)
pool.shutdown()
print('hello')
# 任务函数有返回值时**********************************
def task(res):
# res == 1
print('线程任务开始了...')
time.sleep(1)
print('线程任务结束了...')
return 123
# 回调函数
def call_back(res):
print(type(res))
# 注意: 赋值操作不要与接收的res同名
res2 = res.result()
print(res2)
for line in range(5):
pool.submit(task, 1).add_done_callback(call_back)
pool.shutdown()
print('hello')
넷째, 코 루틴 (사용 하나 개의 스레드 만)
1. 프로세스 / 스레드 / 코 루틴 차이점
- 프로세스 : 자원 단위
- 스레드 : 구현 단위
- 코 루틴 : 단일 스레드 동시성에서
- 참고 : 코 루틴이 아닌 운영 체제의 개념, 그것은 인위적으로 단일 스레드 동시성을 허용하기 위해, 생성 된 이름입니다.
코 루틴 2. 효과
- + 보존 스위칭 상태 : 멀티 채널 기술은 핵심
- 동시에 메모리 멀티 채널 작업을 넣어
- 멀티 채널 작업이 CPU에서 실행 켜 IO 또는 경험 CPU 시간은 전환 너무 깁니다
- 전환 할 때 작업 진행 상황이 저장됩니다
코 루틴
+ 아날로그 시스템의 수동 조작에 의해 저장된 상태 전환 달성 "다중 채널 기술"
CPU, 멀티 프로세스 / 스레드와 같은 여러 작업으로 스레드를 보자.
- 상태를 저장 + 여러 작업 사이에 앞뒤로 스레드 스위치를 만드는 것입니다
- IO 집중적를 들어, IO 스위치 + 상태를 저장 충족
연산 집약적를 들어, 토글 +는 상태를 저장합니다. 연산 집약적를 들어, 낮은 효율 코 루틴의 사용.
장점 :
IO를 많이 사용의 경우, 효율성을 향상시킬 수
단점 :
스위칭 보낸 뒤로 덜 효율적인 계산 집약적의 경우,
3. 코 루틴을 구현하는 방법
(1) 여기서, 계산 집약적
- 사용
yield
상태를 저장 - 전환은 동시입니다
예 :
import time
def func1():
while True:
10000000+1
yield
def func2():
g = func1() # 启动生成器 ,g 为生成器对象
for i in range(10000000):
time.sleep(10) # 模拟IO,yield并不会捕捉到并自动切换
i+1
next(g)
start = time.time()
func2()
stop = time.time()
print(stop-start)
(2) IO 집약적 인 경우
타사 라이브러리를 가져 오려면 :
from gevent import monkey,spawn , joinall
gevent
그것은 우리가 IO 작업 및 스위치를 모니터링하는 데 도움이 될 수 있습니다 타사 라이브러리입니다사용
gevent
+ IO, 보존의 스위칭 상태가 발생 단일 스레드를 달성하기 위해 목적입니다monkey.patch_all()
모든 IO는 수신기에서 작동 할 수 있습니다spawn 和 joinall
저장 상태 스위치가 구현 될 수있다 +
예 :
from gevent import monkey
monkey.patch_all() # 可以监听该程序下所有的IO操作
import time
from gevent import spawn, joinall # 用于做切换 + 保存状态
def func1():
print('1')
# IO操作
time.sleep(1)
def func2():
print('2')
time.sleep(3)
def func3():
print('3')
time.sleep(5)
start_time = time.time()
s1 = spawn(func1) # 传任务
s2 = spawn(func2)
s3 = spawn(func3)
# s2.join() # 发送信号,相当于等待自己 (在单线程的情况下)
# s1.join()
# s3.join()
# 必须传序列类型,如列表和元组
joinall([s1, s2, s3])
end_time = time.time()
print(end_time - start_time)
다섯째, 단일 스레드의 동시 서버 달성
예 :
# 客户端*************************************
import socket
import time
from threading import Thread, current_thread
def client():
client = socket.socket()
client.connect(
('127.0.0.1', 9527)
)
print('启动客户端...')
number = 0
while True:
send_data = f'{current_thread().name} {number}'
client.send(send_data.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
number += 1
# 模拟了300个用户并发去访问服务端
for i in range(300):
t = Thread(target=client)
t.start()
# 服务端*********************************
from gevent import monkey
monkey.patch_all() # 检测IO
import socket
import time
from threading import Thread
from gevent import spawn
server = socket.socket()
server.bind(
('127.0.0.1', 9527)
)
server.listen(5)
print('启动服务端...')
# 线程任务,执行接收客户端消息与发送消息给客户端
def working(conn):
while True:
try:
data = conn.recv(1024).decode('utf-8')
if len(data) == 0:
break
print(data)
# time.sleep(1)
send_data = data.upper().encode('utf-8')
conn.send(send_data)
except Exception as e:
print(e)
break
conn.close()
def server2():
while True:
conn, addr = server.accept()
# print(addr)
# t = Thread(target=working, args=(conn,))
# t.start()
spawn(working, conn)
if __name__ == '__main__':
s1 = spawn(server2)
s1.join()
여섯 동시 프로그래밍 모듈에서 발생
모듈 및 방법 1. 프로세스를 가져와야
from multiprocessing import Process , Lock , RLock , Queue , Semaphore , Event
# 分别用来:创建进程,创建互斥锁,创建递归锁,创建队列,创建信号量 ,创建事件
모듈 및 방법은 스레드 2를 가져와야
from threading import Thread , current_thread , Lock , RLock , queue , Semaphpre , Event
# 分别用来:创建线程,返回当前线程的信息 , 创建互斥锁,创建递归锁,创建队列,创建信号量 ,创建事件
3. 수영장과 풀의 프로세스 모듈 및 스레드의 방법은 수입한다
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
# 分别用来: 创建进程池 , 创建线程池
모듈 및 4 코 루틴을 가져 오는 방법
from gevent import monkey , spawn , joinall
# 分别用来 监听线程中的所有IO操作 , 调用定义的任务 , 让主线程等待所有调用的任务执行结束再结束