python 多任务、并发编程等领域
并发:宏观上并行,微观上串行
并行:宏观上并行,微观上并行
并发:I/O密集型作业 运行态---阻塞态的转化
并行:CPU密集型作业
并发(Concurrent)、并行(Parallesim)、
多线程(Multi Threaded)、多进程(Multiprocessing)、多任务(Multitasking) 、协程(Coroutine)
I/O密集型(I/O-bound)、CPU密集型(CPU-bound)
同步(Synchronous) VS 异步(Asynchronous)
Python中有 线程、进程就是操作系统帮你实现的上下文切换技术,你无需关心进程调度
协程对标的是线程,代替多线程-在用户态实现的上下文切换技术
进程是操作系统中的一个基本概念,表示计算机中的一个独立执行单元。每个进程都拥有独立的内存空间、资源、数据等,可以独立于其他进程并行执行
多进程编程的关键: 进程间的通信和同步,进程间的数据共享,以及进程间的异常处理
多进程的实现方式主要有两种:一种是通过系统函数创建新进程,另一种是通过进程池实现。
进程 multiprocessing :Process Pipe Queue Lock Pool
创建进程:通过调用 multiprocessing 模块中的 Process 类创建进程。
启动进程:通过调用进程对象的 start() 方法启动进程。
定义进程函数:创建一个函数,用于定义进程所执行的任务。
使用队列进行进程间通信:通过使用 multiprocessing 模块中的队列,可以方便地实现进程间的通信。
等待进程结束:通过调用进程对象的 join() 方法,可以等待进程结束。
此外,multiprocessing 还提供了一些常用的同步机制,例如锁、条件变量等
一个进程可以有多个线程,每条线程可以并发执行不同的任务
线程 threading
Thread、Lock、Rlock、Condition、Semaphore、Event、Timer、local
线程有五种状态:新建、就绪、运行、阻塞、死亡
concurrent.futures 模块,concurrent.futures是3.2引入的新库,
在python的多线程threading、多进程multiprocesssing上进一步封装,实现了进程池和线程池
concurrent.futures实现的都是异步操作
它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,
实现了对threading和multiprocessing的进一步抽象(这里主要关注线程池),不仅可以帮我们自动调度线程
实现了对threading和multiprocessing的进一步抽象
asyncio 适合做I/O密集型任务,你看asyncio翻译过来就是异步I/O,讲的就是I/O密集任务。
协程 async、await关键字 yield from yield关键字
yield是控制流程工具,
yield from(3.3引入的关键字)就是打开了一个双向通道,把外层调用方和最内层的子生成器连接起来
asyncio是python3.4引入的库
async、await关键字是python3.5引入的关键字,也是现在最推荐的实现协程对象的方法。因为之前yield、yield from容易和生成器混淆,不能一眼看出这是在做协程。
多线程使用的是抢占式多任务处理(Pre-emptive Multitasking) 异步IO的机制为协作式多任务处理(Cooperative Multitasking)
concurrent.futures
concurrent.futures中引入了future这个对象
Concurrent.futures中还有一个重要的对象叫做执行器(Executor),分为ThreadPoolExecutor和ProcessPoolExecutor两
asyncio
事件循环是asyncio的核心
libuv is a multi-platform support library with a focus on asynchronous I/O.
asyncio 使用单线程、单个进程的方式切换
async/await 是 Python 提供的异步编程 API,
而 asyncio 只是一个利用 async/await API 进行异步编程的框架
JavaScript--event loop(事件循环)
事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务
运行机制:
1.所有同步任务都在主线程上执行,形成一个 执行栈(Execution Context Stack)
2.主线程之外,还存在一个 任务队列(Task Queue)。
只要异步任务有了运行结果,就在 任务队列 之中放置一个事件
3.一旦 执行栈 中的所有同步任务执行完毕,系统就会读取 任务队列,
看看里面有哪些待执行事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
4.主线程不断重复上面的第三步
浏览器中 JavaScript 的执行流程和 Node.js 中的流程都是基于 事件循环 的
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等
调用一个方法的时候,生成一个与这个方法对应的执行环境(context),又叫执行上下文
事件队列(Task Queue
主线程处于闲置状态时,主线程会去查找事件队列是否有任务。
如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码
异步任务之间并不相同,因此他们的执行优先级也有区别。不同的异步任务被分为两类:
微任务(micro task)和宏任务(macro task)
宏任务与微任务的区别在于队列中事件的执行优先级
node中事件循环的实现是依靠的libuv引擎。其他则是浏览器运行环境中由浏览器内核引擎实现
迭代器与生成器
迭代器就是可以被迭代的对象,对其使用next操作可以返回一个元素,通常多次迭代后迭代器会中止,此时迭代器无法再使用。
比如python中可以通过iter方法来将一个列表转换成迭代器:
python中,可以使用yield关键字使函数返回生成器对象
Python 3.5 添加了 async 和 await 这两个关键字,分别用来替换 asyncio.coroutine 和 yield from。
自此,协程成为新的语法,而不再是一种生成器类型了
asyncio的运行原理
了解EventLoop的设计原理
事件循环的创建、获取、设置
运行和停止事件循环
创建Future和Task
事件循环的时钟
计划执行回调函数(CallBacks
阻塞类型
IO调用,如socket,file,pipe等。
人为制造的阻塞,如sleep。
异步调用。
层次:
01.应用开发者通常应当使用高层级的 asyncio 函数,例如 asyncio.run(),
首先创建了一个全新的事件循环。
一旦成功创建,就会接受我们传递给它的任何协程,并运行它直到完成,然后返回结果。
此函数还将对主协程完成后可能继续运行的内容进行清理,
一切完成后,它会关闭并结束事件循环。
02. 低层级代码、库和框架的编写者,他们需要更细致地控制事件循环行为
使用asyncio来进行app开发 框架开发者
asyncio.get_running_loop()
asyncio.get_event_loop()
asyncio.set_event_loop(loop)
asyncio.new_event_loop()
loop.run_until_complete(future)
loop.run_forever()
loop.create_future()
loop.create_task(coro, *, name=None, context=None)
loop.set_task_factory(factory)
coroutine loop.create_connection
coroutine loop.create_datagram_endpoint
传统的asyncio异步事件循环
01.如果不存在事件循环,必须创建一个事件循环--定义协程
02.调用异步函数前要先调用asyncio.get_event_loop()函数获取事件循环loop对象,
03.然后通过不同的策略调用loop.run_forever()方法或者loop.run_until_complete()方法执行异步函数
loop = asyncio.get_event_loop() 1
task = loop.create_task(main()) 2
loop.run_until_complete(task) 3
pending = asyncio.all_tasks(loop=loop)
for task in pending:
task.cancel()
group = asyncio.gather(*pending, return_exceptions=True) 4
loop.run_until_complete(group) 3
loop.close() 5
await一个协程。一般用于在一个协程中调用另一协程 要暂停执行,可使用 await 关键字
用asyncio.create_task()方法将Coroutine(协程)封装为Task(任务)。一般用于实现异步并发操作
任务是协程的包装器,它安排协程尽快在事件循环上运行,并提供一系列的方法来获取协程的运行状态和返回值
应用开发
syncio.run是Python3.7之后新增的入口函数-是asyncio.run()方法,可以省去显式的定义事件循环的步骤。
启动:启动异步应用程序的标准方式是有一个main()协程函数,并用asyncio.run()调用它
协程函数,定义形式为 async def 的函数。
|># more main.py
import asyncio
async def hello():
print('enter hello ...')
return 'world'
if __name__ == "__main__":
rst = asyncio.run(hello())
print(rst)
开发
使用 asyncio 上手还是比较简单。主要是理解事件循环,协程和任务,future的关系
java中
进程(Process):将程序运行起来,我们称之为进程。进程是执行程序的一次执行过程,它是动态的概念
线程(Thread):线程是进程中的实际运作的单位,是进程的一条流水线,是程序的实际执行者,是最小的执行单位。
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程。
线程是CPU调度和执行的最小单位
线程分为用户线程和守护线程。
守护(Deamon)线程
java.util.concurrent.locks.Lock
线程实现:主线程和自定义线程
继承Thread类 扩展java.lang.Thread类
实现Runnable接口 实现java.lang.Runnable接口
C++
1.Linux下一个进程在内存里有三部分的数据,就是“代码段”、“堆栈段”和“数据段”。
2. C++ 11之前: 操作系统平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h> 。
C++11提供了语言层面上的多线程,包含在头文件<thread>中
多线程并发指的是在同一个进程中执行多个线程
std::thread
std::thread是C++ 11提供的原生线程库,它简化了多线程编程,提供了线程创建、管理和同步等基本功能
Boost.Thread库
Boost.Thread库是Boost C++库中的一个子库,提供了线程创建、管理和同步等功能。相较于std::thread,Boost.Thread库提供了更丰富的功能
C++提供如下的异步操作接口:
std::future :异步指向某个任务,然后通过future特性去获取任务函数的返回结果。
std::aysnc :异步运行某个任务函数。 std::promise :线程1设置了某个值,然后通知另外的线程,可以省去消息通信。
std::packaged_task :将任务和feature绑定在一起的模板,是一种对任务的封装
C++标准库使用std::future为一次性事件建模
C++带有线程操作,异步操作,就是没有线程池。
https://github.com/progschj/ThreadPool/blob/master/ThreadPool.h
原理是管理一个任务队列和一个工作线程队列,
工作线程 不断的从任务队列取任务,然后执行;
如果没有任务就挂起休眠等待新任务的到来。
添加新任务的时候先添加到 任务队列,然后通知任意一个线程notify_one
// 工作线程组 need to keep track of threads so we can join them
std::vector< std::thread > workers;
// 任务队列 the task queue
std::queue< std::function<void()> > tasks;
维护一个任务队列用于管理待执行任务。
可使用线程安全的容器(例如deque),配合互斥量(std::mutex)和条件变量(std::condition_variable)实现任务队列的同步访问。
C++中原子变量(atomic)是一种多线程编程中常用的同步机制,它能够确保对共享变量的操作在执行时不会被其他线程的操作干扰,
从而避免竞态条件(race condition)和死锁(deadlock)等问题.
unistd.h为Linux/Unix系统中内置头文件,包含了许多系统服务的函数原型,例如read函数、write函数、getopt函数和getpid函数等
linux
进程
内核为每个进程分配一个 PCB(Processing Control Block)进程控制块,维护进程相关的信息
ps 查看当前终端的进程 getpid库函数的功能是获取本程序运行时进程的编号
fork() 因为一个进程在运行中,如果使用了fork函数,就产生了另一个进程
kill
其一如何将新建连接分发给子进程,其二如何将数据/信号传给子进程,并监控子进程
线程
Linux系统下的多线程遵循POSIX线程接口,称为pthread。
编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a
库
多进程代表的web server是Nginx,Apache等,多线程的有Varnish,gRPC,libevent库
aioprocessing
参考
https://docs.python.org/zh-cn/3/library/asyncio-task.html
https://zhuanlan.zhihu.com/p/343232126
https://github.com/progschj/ThreadPool/blob/master/example.cpp
https://blog.yanjingang.com/?p=4487
https://zhuanlan.zhihu.com/p/636156144
标签:异步,协程,Python,任务,线程,进程,多线程,loop,asyncio
From: https://www.cnblogs.com/ytwang/p/17874600.html