確かに協調マルチタスクです。
それを証明する小さなプログラムはどうでしょうか。まずasyncio.sleep
という共同体で1秒間眠ってから、ブロックtime.sleep
で1秒間寝ましょう。スレッド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
予想通り。実行は1つのスレッドのみでした。 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とは異なり、C#のasync/awaitには、協調的なマルチタスキングとマルチスレッドの組み合わせがあります。Task.Delay(1000)
は実際には非ブロッキングですが、コルーチンが再開すると、例の場合と全く異なるスレッドで再開することができます。コルーチンは3つの異なるスレッドで継続されていたので、Thread.Sleep(1000)
は並行してそれらをブロックしました。
C#ではこの動作(SynchronizationContextなど)に影響する可能性のあるものがありますが、これは別のトピックです。
「待っているコルーチン」はややナンセンスです。 asyncioがstdlibモジュールを参照する "asyncio coroutines"を参照するように質問を変更することを提案して、他のコルーチンシステム(gevent、twistedなど)と区別することはできますか? "await"を使用して式のタイプを記述できます。 –
@GaryvanderMerwe「非同期コルーチン」に変更しました。今大丈夫? – guettli