Python3 协作式多任务处理中是否有 `await`?
Is `await` in Python3 Cooperative Multitasking?
我正在尝试了解新的 asyncio 协程(在 Python 3.5 中引入)。
1997 年我在大学上了一门课程,大致涵盖了 Andrew Tanenbaum 所著Modern Operating Systems一书的内容。
不知何故 Python3 中的 await
让我想起了 Cooperative Multitasking。
来自维基百科:
Cooperative multitasking, also known as non-preemptive multitasking, is a style of computer multitasking in which the operating system never initiates a context switch from a running process to another process. Instead, processes voluntarily yield control periodically or when idle in order to enable multiple applications to be run simultaneously. This type of multitasking is called "cooperative" because all programs must cooperate for the entire scheduling scheme to work.
如果您将 Python 解释器视为操作系统,术语 "Cooperative Multitasking" 适用于 await
吗?
但可能是我遗漏了什么。
Inside a coroutine function, the await expression can be used to
suspend coroutine execution until the result is available. Any object
can be awaited, as long as it implements the awaitable protocol by
defining the await() method.
协程可以使用 await 关键字与另一个协程暂停执行。暂停时,协程的状态会保持不变,允许它在下次被唤醒时从中断处恢复。对我来说,这听起来很像合作式多任务处理。看到这个 example
是的。根据 Wikipedia:
Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.
这确实是协作式多任务处理。
来个小程序来证明一下吧。让我们先用合作 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# 也有 async/await,它也有协作式多任务处理吗?
让我们在 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不同,async/await在C#中结合了协作多任务和多线程。 Task.Delay(1000)
确实是非阻塞的,但是当协程恢复时,它可以恢复在与示例中完全不同的线程中。由于协程在三个不同的线程中继续运行,Thread.Sleep(1000)
并行阻塞了它们。
请注意,C# 中有更多东西可以影响此行为(如 SynchronizationContext),但这是另一个主题。
我正在尝试了解新的 asyncio 协程(在 Python 3.5 中引入)。
1997 年我在大学上了一门课程,大致涵盖了 Andrew Tanenbaum 所著Modern Operating Systems一书的内容。
不知何故 Python3 中的 await
让我想起了 Cooperative Multitasking。
来自维基百科:
Cooperative multitasking, also known as non-preemptive multitasking, is a style of computer multitasking in which the operating system never initiates a context switch from a running process to another process. Instead, processes voluntarily yield control periodically or when idle in order to enable multiple applications to be run simultaneously. This type of multitasking is called "cooperative" because all programs must cooperate for the entire scheduling scheme to work.
如果您将 Python 解释器视为操作系统,术语 "Cooperative Multitasking" 适用于 await
吗?
但可能是我遗漏了什么。
Inside a coroutine function, the await expression can be used to suspend coroutine execution until the result is available. Any object can be awaited, as long as it implements the awaitable protocol by defining the await() method.
协程可以使用 await 关键字与另一个协程暂停执行。暂停时,协程的状态会保持不变,允许它在下次被唤醒时从中断处恢复。对我来说,这听起来很像合作式多任务处理。看到这个 example
是的。根据 Wikipedia:
Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.
这确实是协作式多任务处理。
来个小程序来证明一下吧。让我们先用合作 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# 也有 async/await,它也有协作式多任务处理吗?
让我们在 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不同,async/await在C#中结合了协作多任务和多线程。 Task.Delay(1000)
确实是非阻塞的,但是当协程恢复时,它可以恢复在与示例中完全不同的线程中。由于协程在三个不同的线程中继续运行,Thread.Sleep(1000)
并行阻塞了它们。
请注意,C# 中有更多东西可以影响此行为(如 SynchronizationContext),但这是另一个主题。