我正在尝试理解新的异步协同(在Python3.5中引入)。
1997年,我在大学上了一门课程,大致涵盖了安德鲁·塔宁鲍姆( Andrew )的“现代操作系统”一书的内容。
不知何故,await
in Python3让我想起了合作多任务。
维基百科:
协作多任务处理,也称为非先发制人多任务处理,是一种计算机多任务处理方式,其中操作系统从不启动上下文从一个正在运行的进程切换到另一个进程。相反,进程自愿定期或在空闲时产生控制,以使多个应用程序能够同时运行。这种类型的多任务处理被称为“协作”,因为所有程序都必须配合整个调度方案才能工作。
如果您像看待操作系统一样查看Python解释器,那么“合作多任务处理”一词是否适用于await
?
但也许我错过了什么。
发布于 2016-08-10 05:50:06
在coroutine函数中,等待表达式可用于暂停协同执行,直到结果可用为止。任何对象都可以等待,只要它通过定义等待()方法来实现可访问协议。
一个协同线可以使用与另一个协同线的等待关键字暂停执行。当它被暂停时,协同线的状态被保持,允许它在下一次被唤醒时恢复到它停止的地方。在我看来,这听起来很像合作多任务处理。参见此示例
发布于 2016-08-18 18:13:46
这确实是一项合作的多任务处理。
用一个小程序来证明它呢。让我们先使用协作asyncio.sleep
睡一会儿,然后再用阻塞time.sleep
睡一会儿。让我们打印一个线程id,在任务的协同线和id中花费的时间。
import threading
import asyncio
import time
async def async_function(i):
started = time.time()
print("Id:", i, "ThreadId:", threading.get_ident())
await asyncio.sleep(1)
time.sleep(1)
print("Id:", i, "ThreadId:", threading.get_ident(), "Time:", time.time() - started)
async def async_main():
await asyncio.gather(
async_function(1),
async_function(2),
async_function(3)
)
loop = asyncio.get_event_loop()
loop.run_until_complete(async_main())
现在让我们看看:
Id: 3 ThreadId: 140027884312320
Id: 2 ThreadId: 140027884312320
Id: 1 ThreadId: 140027884312320
Id: 3 ThreadId: 140027884312320 Time: 2.002575397491455
Id: 2 ThreadId: 140027884312320 Time: 3.0038201808929443
Id: 1 ThreadId: 140027884312320 Time: 4.00504469871521
不出所料。执行只在一个线程中。asyncio.sleep(1)
是非阻塞的,所以需要1秒来同时处理它们。time.sleep(1)
是阻塞的(它不合作),所以它阻止了其余的。Id 1
等待id 2
完成,id 2
等待id 3
完成。
C#也有异步/等待,它也有协作多任务处理吗?
让我们在C#中尝试同样的方法:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTest
{
class MainClass {
private static async Task AsyncMethod(int id) {
var started = DateTime.Now;
Console.WriteLine("Id: {0} ThreadId: {1}", id, Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
Thread.Sleep(1000);
Console.WriteLine("Id: {0} ThreadId: {1} Time: {2}", id, Thread.CurrentThread.ManagedThreadId, DateTime.Now - started);
}
private static async Task MainAsync()
{
await Task.WhenAll(AsyncMethod(1), AsyncMethod(2), AsyncMethod(3));
}
public static void Main (string[] args) {
MainAsync().Wait();
}
}
}
运行它然后..。
Id: 1 ThreadId: 1
Id: 2 ThreadId: 1
Id: 3 ThreadId: 1
Id: 2 ThreadId: 7 Time: 00:00:02.0147000
Id: 3 ThreadId: 8 Time: 00:00:02.0144560
Id: 1 ThreadId: 6 Time: 00:00:02.0878160
见鬼。等待之后,线程就不一样了。每条协同线只需2秒!怎么了?
没什么不对。与Python不同,C#中的异步/等待具有协同多任务处理和多线程处理的结合。 Task.Delay(1000)
确实是非阻塞的,但是当协同线恢复时,它可以在一个完全不同的线程中恢复,就像在示例中那样。由于协同工作在三个不同的线程中继续进行,所以Thread.Sleep(1000)
并行地阻止了它们。
注意,C#中有更多的东西可以影响这种行为(比如SynchronizationContext),但这是一个不同的主题。
发布于 2016-08-15 10:26:55
是。根据维基百科的说法:
Coroutines是计算机程序组件,它通过允许多个入口点在某些位置暂停和恢复执行来概括非抢占多任务处理的子例程。
https://stackoverflow.com/questions/38865050
复制相似问题