※当サイトの記事には、広告・プロモーションが含まれます。

Pythonのコルーチン(coroutine)って何なのか

gigazine.net

ジョンズ・ホプキンス大学の暗号学者であるマシュー・グリーン氏が、「Telegramが匿名性の高いアプリだという間違った考えがインターネット上に広まっている」と警鐘を鳴らし、なぜ間違っているのかについてブログで解説しました。

メッセージアプリ「Telegram」が「匿名性が高い」アプリと扱われているのはイメージで実際には全然そんなことはない - GIGAZINE

多くのシステムでは何らかの方法で暗号化を使用していますが、メッセージアプリという文脈で「暗号化アプリ」といえば「標準でエンドツーエンド(E2E)暗号化されていること」を意味するのが一般的です。E2E暗号化が行われるとメッセージの内容は送信した人と受信した人以外が確認することはできず、たとえアプリの開発者や法執行機関であってものぞき見ることはできません。

メッセージアプリ「Telegram」が「匿名性が高い」アプリと扱われているのはイメージで実際には全然そんなことはない - GIGAZINE

しかし、グリーン氏は「TelegramはE2E暗号化を標準では行っておらず、E2E暗号化されたチャットを行うのは一般ユーザーには困難」と指摘。下図はiOS版のTelegramアプリでE2E暗号化を有効化する方法を示したもの。左から順番に4つの手順が必要です。

メッセージアプリ「Telegram」が「匿名性が高い」アプリと扱われているのはイメージで実際には全然そんなことはない - GIGAZINE

⇧ 標準では機能していないかもしれなくても、設定すれば機能するのであれば、悪用しようと思えば悪用できてしまうということで、「犯罪」を助長してしまっている可能性を無くせないってことなんじゃないのかね?

とりあえず、

なお、E2E暗号化をすれば完全に安全というわけではなく、「誰とチャットしたのか」「いつどれくらいチャットしたのか」などのメタデータはE2E暗号化をしていても筒抜けです。グリーン氏は「暗号化だけで十分だという結論に陥らないように」と注意しつつ、「Telegramについての誤解を訂正しないと多くのユーザーが大きな損害を被る可能性がある」とブログを投稿した理由を書き残しています。

メッセージアプリ「Telegram」が「匿名性が高い」アプリと扱われているのはイメージで実際には全然そんなことはない - GIGAZINE

⇧「犯罪」を取り締まる側としては、「会話内容」が知りたいと思うので、「犯罪」に関する捜査では、復号化とかできるようにとか、何某かの対応は必要な気がしますが...

「Telegram」がターゲットとしたい利用者が分からないので、何とも言えませんが、

  • Telegram側
    犯罪目的で利用したかが把握・確認できる(捜査に協力できる)
  • 司法側
    法律で罰することができるようにする

のような体制が作れれば良い気はしますが。

日本の「法務省」の公開しているドキュメントによると、

www.moj.go.jp

通信傍受の対象となる犯罪は,薬物関連犯罪銃器関連犯罪集団密航の罪組織的殺人ですが,これら組織的な犯罪では,その準備及び実行が密行的に行われ,犯行後にも証拠を隠滅したり,犯人を逃亡させるなどの工作が行われることも少なくなく,それらを実行するための手段として,しばしば電話等の通信手段が悪用されております。
 また,犯行に関与した末端の者を検挙しても,首謀者等の氏名や関与の状況について供述を得ることは容易ではありません
 そこで,通常の捜査方法では真相の解明が困難であるこれら犯罪のための特別な捜査手法として通信傍受を認めることが,今日の組織犯罪に対抗するためには,どうしても必要なのです。
 なお,主要先進諸国のほぼすべてにおいて通信傍受制度に関する法整備がなされており,我が国においてもこれを整備することが国際的要請になっています。

⇧ とあり、「犯罪捜査」においては「通信傍受」を認めてそうなこともあり、

www.itmedia.co.jp

 Telegramは秘匿性の高さが特徴で、香港デモ参加者ウクライナ政府ロシア政府を告発する個人なども安全な情報伝達手段として活用する半面、この秘匿性により、犯罪者が法執行機関の追跡を逃れるための連絡手段として使うことも多いと指摘されている。現在のアクティブユーザ数は約10億人。

TelegramのCEOを仏当局が逮捕 「悪用の責任をCEOが負っているという主張は不合理」とTelegram - ITmedia NEWS

 仏当局は、ドゥーロフ氏がTelegramの犯罪目的の悪用を抑制する措置を講じなかったため逮捕したとしている。

TelegramのCEOを仏当局が逮捕 「悪用の責任をCEOが負っているという主張は不合理」とTelegram - ITmedia NEWS

 Telegramは25日、公式アカウントで発表した声明文で、「プラットフォームまたはその所有者がそのプラットフォームの悪用の責任を負っていると主張するのは不合理だ」と主張した。

TelegramのCEOを仏当局が逮捕 「悪用の責任をCEOが負っているという主張は不合理」とTelegram - ITmedia NEWS

⇧ 逮捕までの経緯が分からないのですが、フランスの警察当局側も「Telegram」側もお互い歩み寄りが必要な気がしますが...

『犯罪目的の悪用を抑制する措置』というのが具体的にどういうことを期待しているのかが分かりませんが、最低限「犯罪捜査」に協力できる体制を構築できないかの検討はして欲しいですな。

Pythonのコルーチン(coroutine)って何なのか

Pythonの公式のドキュメントによると、

docs.python.org

⇧ という説明になっておりますと。

(コルーチン) コルーチンはサブルーチンのより一般的な形式です。 サブルーチンには決められた地点から入り、別の決められた地点から出ます。 コルーチンには多くの様々な地点から入る、出る、再開することができます。 コルーチンは async def 文で実装できます。 PEP 492 を参照してください。

う~む、頭の悪い吾輩には「コルーチン」が何なのか全く分からないのだが...

docs.python.org

18.5.3. タスクとコルーチン

18.5.3.1. コルーチン

単語 "コルーチン" は単語 "ジェネレーター" のように、(関連はしていますが) 異なる 2 つの概念で使用されます:

  • コルーチンを定義した関数 (async def を使用するか @asyncio.coroutine でデコレートされた関数定義)。 曖昧さを避ける際は コルーチン関数 と呼びます (iscoroutinefunction() は True を返します)。

  • コルーチン関数の呼び出しによって取得されたオブジェクト。このオブジェクトは、いつかは完了する計算または I/O 操作 (通常はその組み合わせ) を表します。曖昧さの解消が必要な場合はこれを コルーチンオブジェクト (iscoroutine() が True を返す) と呼びます。

https://docs.python.org/ja/3.6/library/asyncio-task.html

18.5.3.1.3. 例: コルーチンのチェーン

コルーチンをチェーンする例です:

https://docs.python.org/ja/3.6/library/asyncio-task.html

compute() は print_sum() にチェーンされます: print_sum() コルーチンは compute() が完了するまで待ちます。

https://docs.python.org/ja/3.6/library/asyncio-task.html

この例のシーケンス図です:

https://docs.python.org/ja/3.6/library/asyncio-task.html

Pythonでは「async def」で定義された関数を「コルーチン」とするということですかね?

と思ったら、

18.5.3.1. コルーチン

asyncio と一緒に使うコルーチンは async def 文を使って実装するか、もしくは ジェネレータ を使って実装します。async def 型のコルーチンはPython 3.5の時に追加されました。3.5より前のバージョンのPythonをサポートする必要がなければ async def タイプのコルーチンが推奨されています。

https://docs.python.org/ja/3.6/library/asyncio-task.html

⇧ 上記は、あくまで、「asyncio」で「コルーチン」を利用する場合の話であるので、「コルーチン」は使われ方で、実装内容が変わってくるという...

というわけで、

  • 「asyncio」利用しない場合でも「コルーチン」って利用できるのか?
  • 「asyncio」利用しない場合は、「コルーチン」の実装内容が変わるのか?
  • 結局のところ、「コルーチン」の利用パターンの全量はいくつあるのか?

と分からないことだらけなんだが...

一般的なコルーチン(co-routine)とは?

う~む、ちょっと、Pythonの「コルーチン(coroutine)」の説明が分からな過ぎるので、一般的な「コルーチン」について確認してみますか。

コルーチンco-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。

コルーチン - Wikipedia

サブルーチンと異なり、状態管理を意識せずに行えるため、協調的処理、イテレータ、無限リスト、パイプなど、継続状況を持つプログラムが容易に記述できる。

コルーチン - Wikipedia

コルーチンはサブルーチンを一般化したものと考えられる。コルーチンをサポートする言語には Modula-2SimulaIconLuaC#LimboSwift などがある。

コルーチン - Wikipedia

⇧ うむ、分からん。

「サブルーチン」を確認してみる。

プログラミングにおけるサブルーチンsubroutine)は、プログラム中で意味や内容がまとまっている作業をひとつにまとめたものである。

サブルーチン - Wikipedia

サブプログラムあるいは副プログラムsubprogramとも呼ばれ、単に「ルーチン」(routine)と呼ばれることもある。プログラミング言語によっては、関数function)やプロシージャあるいは手続きprocedure)とも呼ばれる。

サブルーチン - Wikipedia

⇧ うむ、分からん。

が、「RDBMS(Relational DataBase Management Systems)」に出てくる「ストアドプロシージャ」と「サブルーチン」は同じものってことになるんかね?

『「コルーチン」は「サブルーチン」を一般化したもの』というのがどういうことなのか分からんのだけど、「コルーチン(coroutine)」に話を戻すと、

マルチスレッドで理論的には同じことができるため、現在はそちらが使われるケースが多い。

コルーチン - Wikipedia

これはマルチスレッドであれば直接OSやCPUスレッドの支援を受けられることや、エントリー/リターンの構造を変えずにコードを多重化できるので、過去の言語との親和性が良いなどが理由である。

コルーチン - Wikipedia

一方、マルチスレッドの場合はプログラマがスレッド間の同期や排他制御を行わなければならないが、その結果スレッドが実行を続けられなくなった場合は別のスレッドを実行するために暗黙的にコルーチンを呼び出す。この点では、マルチスレッドはコルーチンの抽象度をより高めた応用と解釈することができる。

コルーチン - Wikipedia

Pythonは「GIL(Global Interpreter Lock)」のせいで「マルチスレッド」の効果が薄いらしいからして「コルーチン」が進化していった感じなんかね?

「マルチプロセス」であれば、「GIL(Global Interpreter Lock)」の影響を無視できるとは思いますが。

その割には、Wikipediaで『コルーチンをサポートする言語』に「Python」が取り上げられていないのが気になりますが...

言語仕様以外の例では、マルチタスクOSやユーザスレッドにおけるコンテキストスイッチがコルーチンとなる。

コルーチン - Wikipedia

この点では、上記の問題は「コルーチンを言語仕様とOSやスレッドライブラリのどちらに持たせるか」とも解釈できる。

コルーチン - Wikipedia

この場合でもコルーチンをスレッドやタスクのスリープのために明示的に呼び出すだけでなく、割り込みや例外処理の結果暗黙的に実行する場合の両方がある。

コルーチン - Wikipedia

⇧ うむ、余計にPythonの「コルーチン」が何なのか分からなくなった感はある。

スレッド(thread)とコルーチン(coroutine)

とりあえず、「Computer science」において、一般的な

  • routine
  • subroutine
  • coroutine

の関係がよく分からないのだが、

「スレッド(thread)」と「コルーチン(coroutine)」の関係は、

manfonly.medium.com

⇧ 上図のような感じになるらしい。

一般的な「スレッド(thread)」は、

⇧ 上図のような感じの立ち位置になりますと。

サブルーチン(subroutine)とコルーチン(coroutine)

Pythonの「サブルーチン(subroutine)」と「コルーチン(coroutine)」が同じ様な振る舞いになるのかは分からないのですが、C++では、

medium.com

⇧ 上図のような処理の違いになるらしい。

Pythonの公式のドキュメントによると、

docs.python.org

(非同期ジェネレータ) asynchronous generator iterator を返す関数です。 async def で定義されたコルーチン関数に似ていますが、 yield 式を持つ点で異なります。 yield 式は async for ループで使用できる値の並びを生成するのに使用されます。

とあり、「コルーチン(coroutine)」だからといって、「yield 式」が必ずあるとは限らないようですと。

改めて、Pythonのコルーチン(coroutine)って何なのか

一般的な「コルーチン(co-routine)」はさておき、Pythonにおける「コルーチン(coroutine)」は、

⇧ とあるので、

サブルーチンには決められた地点から入り、別の決められた地点から出ます。 コルーチンには多くの様々な地点から入る、出る、再開することができます。

の説明が分かり辛過ぎるのだけど、Wikipediaの「コルーチン(co-routine)」の説明にある、

コルーチンco-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。

コルーチン - Wikipedia

サブルーチンと異なり、状態管理を意識せずに行えるため、協調的処理、イテレータ、無限リスト、パイプなど、継続状況を持つプログラムが容易に記述できる。

コルーチン - Wikipedia

⇧ 上記のような振舞いが実装されているものであって、Pythonにおいては、「非同期処理」でも「コルーチン(coroutine)」が利用されると。

「PEP492」の概要で、

peps.python.org

Abstract

It is proposed to make coroutines a proper standalone concept in Python, and introduce new supporting syntax. The ultimate goal is to help establish a common, easily approachable, mental model of asynchronous programming in Python and make it as close to synchronous programming as possible.

https://peps.python.org/pep-0492/

⇧とあるので。

とりあえず、

www.rhoboro.com

ちなみに「ネイティブコルーチン」呼んでいるのは「ジェネレータベースのコルーチン」というものがPythonには古くからあるためです。 @asyncio.coroutineをつけるとネイティブコルーチンと相互利用が可能ですが、ジェネレータベースのコルーチンはPython 3.10でなくなる予定です。

コルーチンは怖くない

postd.cc

ネイティブコルーチンとジェネレータベースのコルーチンの間で機能的な違いはありませんが、構文だけ異なります。

https://postd.cc/python-generators-coroutines-native-coroutines-and-async-await/

⇧ 上記サイト様によりますと、Pythonの「コルーチン」の実装方法としては、大きく分けて、

  1. Generator-based Coroutines
  2. native coroutine

の2つに分類できるそうな。

docs.python.org

⇧『注釈: Support for generator-based coroutines is deprecated and is removed in Python 3.11.』とあるので、「2. native coroutine」を実現する「async/await構文」での実装方法を利用していく感じになると。

Pythonの公式のドキュメントの分かり辛さ、何とかならんもんか...

結局、Pythonの「コルーチン(coroutine)」がよく分からないんだが...

毎度モヤモヤ感が半端ない…

今回はこのへんで。