标签:时间段 title print 系统 读写 子进程 总结 守护进程 提高效率
目录
单道:一台哦到
多道:
并发:看起来像是同时运行
并行:真正意义上的同时运行
并行与并发的区别:
并行是从微观上,也就是一个精确的时间片刻,有不同的程序在执行
并发是从宏观上,在一个时间段上可以看出是同时执行的
进程是资源单位,每创建一个进程都会生成一个名称空间,占用内存资源
程序就是一堆代码
进程:狭义上来讲一堆代码运行的过程;广义上讲,进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是操作系统动态执行的基本单元
同步:执行一个操作之后,等待通知,然后才执行接下来的操作
异步:执行一个操作之后,可以去执行其他的操作,然后等待通知 回来执行未完成的操作。
阻塞:进程给cpu传达一个任务之后,一直等待cpu处理完成,然后才执行接下来的操作
非阻塞:进程给cpu传达任务后,继续处理后续的操作,隔段时间再来询问之前的操作是否完成。
阻塞与非阻塞是指进程访问的数据,如果尚未就绪,进程是否需要等待,指的是一种状态。
同步与异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后,在读写的时候必须阻塞;异步则指主动请求数据后,便可以继续处理其它任务,随后等待I/O操作完毕的通知,这可以使进程在数据读写时也不阻塞。
使用multiprocessing
模块
# 方法一
from multiprocessing import Process
import time
def task():
print('子进程开始。。。')
time.sleep(2)
print('子进程结束。。。')
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join() # 等待所有子进程结束后,主进程才结束
print('主进程')
# 方法二:
class MyProcess(Process):
def run(self) -> None:
print('子进程开始。。。')
time.sleep(2)
print('子进程结束。。。')
if __name__ == '__main__':
p = MyProcess()
p.start()
p.join()
print('主进程')
僵尸进程:子进程结束,PID号还在,主进程没有回收子进程资源
孤儿进程:子进程没有结束,但是主进程意外死亡,操作系统优化机制会将子进程结束之后回收资源。
守护进程:
from multiprocessing import Lock
进程间数据不共享,但共享同一套文件系统,多个进程访问同一个文件会造成混乱、数据不安全,必须加锁。
总结:加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,这样虽然牺牲了效率,但保证了数据的安全
from multiprocessing import Lock
mutex = Lock()
mutex.acquire()# 加锁
# 修改数据的操作
mutex.release()# 释放锁
进程间数据是隔离的,需要通过队列的方式进行通信
FIFO队列:先进先出
from multiprocessing import Queue
q = Queue(5)
q.put() #添加数据,若队列满了,则等待
q.put_nowait() # 添加数据,若队列添加数据满了,就会直接报错
q.get() # 若队列中没有数据,就会卡住等待
q.put_nowait() # 若队列中没有数据,会直接报错
LIFO:后进先出
生产者:生产数据
消费者:使用数据
通过队列实现,生产者将数据扔进队列中,消费者从队列中获取数据,从而平衡了生产者与消费者的处理能力
进程是资源单位,而线程是执行单位。
创建进程会自带一个线程,一个进程下可以创建多个线程
使用线程可以节省资源的开销
进程的优点:
进程的缺点:
线程的优点:
线程的缺点:
总结:GIL锁主要是为了保证线程安全的,保证数据安全
指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,它们都无法推进下去,这就是死锁现象。
from threading import Lock
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()
解决死锁现象
mutex = Lock()
mutex1, mutex2 = Rlock() # 可以引用多次
只要这把锁计数为0,就释放该锁,让下一个人使用
from threading import Semaphore
信号量也是一把锁,可以让多个任务一起使用
可以控制线程的执行,让一些线程控制另一些线程的执行
e = Event()
- 线程1
e.set() # 给线程2发送信号,让他执行
- 线程2
e.wait() # 等待线程1的信号
线程间数据不安全的情况下使用线程队列,保证线程间数据安全
import queue
FIFO: 先进先出队列 queue.Queue()
LIFO: 后进先出队列 queue.LifoQueue()
优先级队列:根据数据大小判断出队列优先级;进队列数据是无序的
queue.PriorityQueue()
为了控制进程/线程创建的数量,保证了硬件能正常运行
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ThreadPoolExecutor
poo1 = ProcessPoolExecutor() # 括号里不加数字表示默认
poo2 = ThreadPoolExecutor(100)
# 将函数地址的执行结果,给回调函数
pool2.submit(任务函数地址,参数).add_done_callback(回调函数地址)
回调函数(必须接收一个参数res)
res2 = res.result() # 获取值
单线程下实现并发,不是任何单位
单线程下实现并发,好处是节省资源
手动创建协程:
第三方模块,用gevent可以实现监听IO操作
from gevent import monkey
monkey.path_all() # 监听所有IO
from gevent import spawn, joinall # spawn实现切换 + 保存状态
s1 = spawn(任务1)
s2 = spawn(任务2)
joinall([s1, s2])
标签:时间段 title print 系统 读写 子进程 总结 守护进程 提高效率
原文地址:https://www.cnblogs.com/setcreed/p/11748693.html