シヌサむド2.9郚分的続線

しばらく前にhabrで、HabrUser qmaxからの「継続」に関するトピック が滑りたした 。 圌はこのアむデアに非垞に感銘を受けたしたが、詳现を䌝えるこずはできたせんでした。 そしお最近、Seasideの開発者の䞀人であるJulian Fitzellは、その明快さに関しお驚くべき蚘事を曞きたした。 圌の蚱可を埗お、私はそれを翻蚳し、habrasocietyず共有したいず思いたす。



すぐに甚語に぀いお蚀いたいず思いたす。 継続ずいう蚀葉の翻蚳ずしお、「継続」ずいう意味で最も近いものを䜿甚したす。 Smalltalkの経隓の浅い開発者向けの蚘事の䞀般的な甚語は、珍しいように思えるかもしれたせん。 したがっお、呌び出しスタックの代わりに「コンテキストのチェヌン」が䜿甚され、スレッドの代わりに「プロセス」が䜿甚されたす。 読んでもただ質問がある堎合は、コメントで自由に質問しおください。 ありがずう



これは、Seasideの今埌のリリヌスに関する䞀連のレビュヌの2番目の投皿です。 䟋倖凊理に関する最初の投皿をご芧ください 。



シヌサむドに続く



シヌサむドは「継続ベヌス」のWebフレヌムワヌクず呌ばれるこずが倚く、実際、開発の倜明けには、魔法を描くためにあらゆる堎所で続線が䜿甚されたした。 Seaside 2.8は、次の3぀の異なるケヌスでファヌストクラスの拡匵機胜を䜿甚したす埌で説明したす。



ただし、Seasideの今埌のリリヌスでは、フレヌムワヌクのコアでの拡匵機胜の䜿甚が完党に排陀されたす。 これらのケヌスの最初のケヌスは䟋倖を䜿甚しお再実装され、2番目ず3番目のケヌスのコヌドはオプションですが、むンストヌルパッケヌゞで利甚可胜になりたす。 ぀たり、継続をたったく䜿甚せずにSeasideをむンストヌルできたす。 この事実は、珟圚継続をサポヌトしおいないSmalltalk方蚀間の移怍性を改善するはずです。



同時に、ファヌストクラスの拡匵機胜も郚分的な拡匵機胜に眮き換えたす。この蚘事では、これが䜕を意味するのか、なぜこれらの倉曎を行うのかを説明する必芁がありたす。 これはすべお、特にデバッグ䞭にバヌを䞋げる可胜性があるため、心配する必芁はありたせんが、情報を萜ち着かせおから、それに戻っお読み盎しおください。 続線のアむデアそのものに困惑しおいる人々がこのトピックをより理解しやすいものにするこずを期埅しお、詳现を犠牲にしおいく぀かのこずを簡略化したした。 このバランスをどのように維持したかに぀いおのフィヌドバックを受け入れたす。



続線ずは



たず、継続に぀いお蚀及するずき、私は最初のクラスの継続を意味したす。 Seasideは、継続転送メ゜ッドを䜿甚しおレンダリングサむクルを実装したすこれは、Seasideによっお生成されたURLに衚瀺される_kパラメヌタヌです。 これは密接に関連する抂念ですが、これから説明するものではありたせん。



継続はしばしば「残䜙蚈算」ずしお定矩されたすが、この珟象の本質をただ理解しおいない堎合、これは少しあいたいな定矩であるず思いたす。 私にずっお最も簡単な説明は、継続によっお実行䞭のプロセスの「スナップショット」が保存され、埌で継続できるこずです。 別のメ゜ッドを呌び出す別のメ゜ッドを呌び出すメ゜ッドを呌び出したす。その埌、この䞀連の呌び出しのスナップショットを取埗し、スナップショットオブゞェクトをどこかに保存したす。 将来、珟圚実行䞭のコヌドを砎棄するこずでい぀でも埩元でき、プログラムはその堎所から、「スナップショット」に蚘録された方法から実行を継続したす。 これは、最初のクラスの続きです。



Smalltalkナヌザヌは、Smalltalkむメヌゞを保存しお埌で開くず、保存時ずたったく同じ画像が衚瀺されるため、理解しやすくなっおいたす。 保存した画像は䜕床でも開くこずができ、そのたびに同じ状態に戻りたす。 むメヌゞを新しいファむルに保存するず、叀いファむルに戻るこずができたす。 継続は、原則ずしお、画像党䜓ではなく同じこずを行い、唯䞀のプロセスを保存したす。



「通話ず応答」の実装



Seasideの最も玠晎らしい機胜の1぀は、通垞の反埩スタむルでナヌザヌの参加を必芁ずするマルチステップタスクを䜜成する機胜です。

answer := self confirm: 'Do it?'.

answer ifTrue: [ self doItAlready ]







これは、継続を䜿甚する堎合に簡単になるものです。メ゜ッドの途䞭で停止し、ナヌザヌに情報の入力を求めたす。 圌が答えたら、䞭断したずころから実行を続けたいず思いたす。 それでは、これを実珟するためにファヌストクラスの拡匵機胜を䜿甚する方法を芋おみたしょう。



チャヌトの読み方



小さな䜙談。 次の図は、コンテキストチェヌンを瀺しおいたすただし、それらはフレヌムスタックず呌ばれるほど抜象的です。 メ゜ッドを呌び出すたび、たたはブロックを実行するたびに、チェヌンの「䞊郚」に新しいコンテキストが䜜成されたす。 メ゜ッドが倀を返すか、ブロックが終了するたびに、「䞊」からのコンテキストが削陀されたす。 メ゜ッドのコンテキストは、どのメ゜ッドがそれを呌び出したか、どのオブゞェクトが呌び出されたか、およびこのメ゜ッドで定矩された倉数の倀を知っおいたす。 圌はたた、チェヌン内の圌の䞋のコンテキストを知っおいたす。 このプロセスを理解するのに助けが必芁な堎合は、むラストをご芧ください。すべおが段階的に描かれおいたす。











次の図は、単䞀のHTTP芁求を凊理するためのコンテキストのチェヌンを衚しおいたす。 各リク゚ストは、コヌルバックを生成するリンクをクリックした結果です。 各コヌルバックは、最終的に#call:



たたは#answer:



送信したす#answer:







図は、 #call:



たたは#answer



ずきにコンテキストのチェヌンを瀺し、次に䜕が起こったかを瀺しおいたす。 䞊矢印はメ゜ッドを呌び出したずきの進行状況を瀺し、䞋矢印はメ゜ッドが完了したずきを瀺したす。 䟋倖を砎線の矢印の圢で瀺したす。その尟は䟋倖の発生堎所にあり、頭はその凊理の堎所を瀺しおいたす。 継続が保存される堎合、䞡方のチェヌンがダむアグラムに衚瀺されたす。珟圚実行されおいるチェヌンず保存されおいるチェヌン。 矢印は通垞どおりに向けられたす。 明らかに、これらは非垞に簡略化された図です。具䜓的な詳现よりも䞀般的なアむデアを説明するこずに興味がありたす。



明確にするために、各チャヌトに灰色のバヌがマヌクされおいたす。 その䞊にあるのはナヌザヌコヌドです。実行されるコヌルバックの䞀郚です。 行の䞋にあるものはすべお、フレヌムワヌクの䞀郚です゜ケットからの読み取り、セッションの管理など。



ナむヌブfr。実装



さお、継続を䜿甚しお可胜な実装の1぀を芋おみたしょう。 ナヌザヌが「do it」リンクを含むWebペヌゞにいるずしたす。 リンクをクリックするず、䟋ずしお䞊蚘のコヌルバックが実行されたす。ナヌザヌは「Do it」ず尋ねる必芁がありたす。 この芁求を凊理する過皋で、次のこずが発生したす。









  1. フレヌムワヌクは正しいコヌルバックを怜玢しお実行したす。
  2. コヌルバックの実行䞭䞊蚘の䟋の#informメ゜ッド内、メッセヌゞ#call:



    送信されたす。
  3. 各コンテキストの結果は、継続䜿甚のために保存されたす。
  4. コヌルバック凊理を停止し、制埡をフレヌムワヌクに返す䟋倖がスロヌされたす。
  5. フレヌムワヌクは匕き続き動䜜し、応答をブラりザヌに返したすSeasideでは、応答のコンポヌネントを衚瀺するためにレンダリングフェヌズが実行されたすが、ここでは少し簡略化したす。




その結果、ブラりザには「Do it」プロンプトずアクションを確認するリンクたたはボタンが衚瀺されたす。 ナヌザヌがこのリンクたたはボタンをクリックするず、コヌルバックがアクティブになり、 self answer: true.



が実行されself answer: true.



。 そしお、2番目の芁求が受信されるず、次のこずが起こりたす。











  1. フレヌムワヌクは、察応するコヌルバックを怜玢しお実行したす。
  2. #answer:



    は#answer:



    メッセヌゞを送信したす。
  3. 珟圚のコンテキストのチェヌンは砎棄され、継続で保存したコンテキストはその堎所に埩元されたす。 このメ゜ッドは2回目に返されるこずに泚意しおください。 これはもちろん奇劙ですが、コンピュヌティングの最䞭にSmalltalkむメヌゞを保存するこずほど奇劙ではありたせん。 画像を開くたびに、同じ蚈算の結果が衚瀺されたす。
  4. 前のコンテキストチェヌンを埩元したので、 #call:



    継続を保存した堎所ぞの呌び出しが#call:



    したかのように、最初のコヌルバックで実行が継続されたす
  5. 埩元されたコヌルバックは実行を完了したすこの䟋では、ナヌザヌの応答の倀をチェックし、 #doItAlready



    を送信し#doItAlready



    
  6. フレヌムワヌクは、ブラりザヌに応答を送信したす。




しかし、問題があるため、この実装をナむヌブず呌んでいたす。 ご芧のずおり、最初のリク゚ストで答えが誀っお返されたす。 残念ながら、最初のリク゚ストに関連付けられた゜ケットは長い間閉じられおおり、ブラりザは回答を埅っおいたせん。 ブラりザは、明らかにリク゚スト番号2に関連付けられた゜ケットに到達しない回答を受け取るこずを期埅しおいたす。 おっず



ほが䜜業䞭の電話ず応答



したがっお、最初の実装は機胜したせんが、続線に䜕が起こるかを瀺しおくれるこずを望みたす。 問題は、継続を埩元するずきに、フレヌムワヌクが行ったすべおを絶察に捚おたくないこずです。 少なくずも、正しい゜ケットに応答を返すコンテキストが必芁です。



継続によっおキャプチャされるコンテキストの数を制限する簡単な方法は、新しいプロセスを䜜成するこずです。 新しいプロセスは、新しい空のコンテキストチェヌンから始たりたす。そのため、継続を䜜成するず、このチェヌン内のコンテキストのみがキャプチャされたす。 セマフォを䜿甚しお、新しいプロセスがリク゚ストを凊理しおいる間、最初のプロセスを埅機させるこずができたす。 2番目のプロセスが完了するず、セマフォに点火し、元のプロセスは正しい゜ケットに応答を返したす。



次の図は、この図を瀺しおいたす異なるプロセスのコンテキストは異なるシンボルで衚されたす。







  1. フレヌムワヌクのコヌドのある時点で、新しいプロセスが䜜成され、元のプロセスはセマフォ信号を予期したす。
  2. 新しいプロセスは、リク゚ストに察応するコヌルバックを芋぀けお実行したす。
  3. #call:



    はメッセヌゞ#call:



    送信したす#call:



  4. 継続は保存されたす今回は継続が新しいプロセスの開始点から開始するこずに泚意しおください。
  5. 䟋倖がスロヌされ、コヌルバックは凊理を停止し、制埡をフレヌムワヌクに返したす
  6. フレヌムワヌクは、ブラりザヌの応答を䜜成し、セマフォに点火したす。
  7. 元のプロセスが続行され、ブラりザヌに応答が返されたす。




これたでのずころ、唯䞀の利点は継続が少ないこずです。 しかし、2番目のリク゚ストが到着するず、このアプロヌチが問題をどのように解決するかが明らかになりたす。







  1. フレヌムワヌクのコヌドのある時点で、新しいプロセスが䜜成され、元のプロセスはセマフォ信号を予期したす。
  2. 新しいプロセスは、リク゚ストに察応するコヌルバックを芋぀けお実行したす。
  3. #answer:



    は#answer:



    メッセヌゞを送信したす。
  4. 珟圚のコンテキストのチェヌンは砎棄され、継続で保存したものが埩元されたすただし、今回は生成されたプロセスのコンテキストのみが砎棄され、保留䞭のプロセスは圱響を受けないこずに泚意しおください。
  5. 保存されたコンテキストチェヌンを埩元した埌、 #call:



    の呌び出しが#call:



    したかのように実行が続行されたす。
  6. コヌルバックは実行を完了したす。
  7. フレヌムワヌクはブラりザの応答を䜜成し、セマフォに点火し、芪プロセスに䜜業の完了を通知したす。
  8. 元のプロセスは実行を継続したすが、今回はブラりザに正しく応答を返したす。




これで、継続が小さくなっただけでなく、2番目の芁求に察する応答が意図したずおりに返されるようになりたした。 Seaside 2.8以前で䜿甚されたのはこの実装です。



しかし、いく぀かの重倧な問題がありたす。

  1. プロセス間通信を䜜成するず、システムの耇雑さが増したす。
  2. 䟋倖は、新しいプロセスが䜜成された境界を越えるこずはできたせん。 実際、䟋倖をスロヌするず、最初のプロセスはそれを知るこずはありたせん技術的には乗り越えられ、ある皋床この動䜜をシミュレヌトできたすが、これはシステムをさらに耇雑にしたす。 これは、生成されたプロセスで゚ラヌ凊理を完党に実行する必芁があるこずを意味したす。 これにより、たずえば、䟋倖を䜿甚しおオブゞェクトを「ダヌティ」ずしおマヌクしたり、珟圚のプロセスのトランザクションステヌタスを瀺したりするデヌタベヌスを操䜜する堎合にも、困難が远加されたす。
  3. 埩元の続行埌にスロヌされた䟋倖は、埩元されたコンテキストのチェヌンを通過したす。 たた、䟋倖が凊理されるず、コンテキストの埩元されたチェヌンは巻き戻され、スロヌされたものではありたせん。 最埌の図の赀で色付けされたフレヌムワヌクコンテキストを芋おください。実行を完了する機䌚がなく、それらによっお定矩されたすべおの安党ブロックが実行されるこずはありたせん。 これがいく぀かの陰湿なバグを匕き起こす可胜性があるず蚀うずき、私を信じおください。
  4. ポむント2ず3に関しお、 サむズず粟床の劥協点を探す必芁がありたす。コヌルバックを実行する盎前に新しいプロセスを開始するず、非垞に小さな継続ずより短い䟋倖凊理が埗られたす。 残念ながら、䟋倖を十分にスロヌするこずはできず、コヌドは完党に異なる堎所、たずえばレンダリングフェヌズで実行を終了したす。
  5. コヌドが実行䞭のプロセスに䟝存しおいる堎合、 デバッグは悪倢になりたす 少なくずもSqueakでは。 デバッガヌが゚ラヌが盎接発​​生したプロセスに進む方法を孊習するかどうかはわかりたせんが、少なくずも゚ラヌなしでこれを行うこずはできたせん。


郚分継続



郚分的な続線は、コンテキストのチェヌン党䜓を保持する代わりに、関心のある郚分のみを保持するこずを意味したす。 そしお、郚分継続を埩元する堎合、チェヌン党䜓ではなく、関心のない郚分のみを眮き換えたす。 それがどのように機胜するかを芋おみたしょう。









最初のリク゚ストが到着するず、すべおが最初の䟋ずたったく同じように発生するため、段階的な分析は行いたせん。ただし、1぀を陀きたす郚分的な拡匵子を䜿甚しお、継続で保存するコンテキストの正確な範囲を指定できたす。 この堎合、ナヌザヌコヌドの䞀郚であるコヌルバックのみを保存したす。 最初の実装の問題を芚えおいたすか フレヌムワヌクコヌドは1぀の特定の芁求を凊理したす。 これらのフレヌムワヌクコンテキストは、他のリク゚ストを凊理する際にはたったく圹に立ちたせん同じURLであっおも、新しいリク゚ストがありたす。 コヌルバックは実行䞭に耇数のHTTPリク゚ストをカバヌできるため、将来の埩元のためにこれらのリク゚ストに応じおコヌルバックコンテキストのみを保存する必芁がありたす。



たた、実際のコンテキストチェヌンはこれらの図に瀺されおいるよりもはるかに長くなる可胜性があるこずを忘れないでください。したがっお、たずえば40の代わりに5぀のコンテキストを保存したす。 たあどう 良い節玄。



次に、2番目のリク゚ストがどのように凊理されるかを芋おみたしょう。 この図は、実行時にコンテキストのチェヌンが倉化するため、少し異なり、より耇雑です。そのため、ステップごずに説明したす。









  1. 芁求は凊理䞭です。
  2. フレヌムワヌクは適切なコヌルバックを怜玢しお実行したす。
  3. #answer:



    は#answer:



    メッセヌゞを送信したす。
  4. 次に、既存のコヌルバックコヌドの代わりに保存された郚分継続が怜玢され、保存されたコンテキストが珟圚のコンテキストに文字通り「移怍」され、メッセヌゞ送信者が曞き換えられたす。 私は空䞭で手を動かし、现郚を省きたすが、あなたは私を信じなければなりたせん、すべおが実際にそのように起こりたす。 図の右偎は、「移怍」の完了埌の状態を瀺しおいたす。 フレヌムワヌクのすべおのコンテキストは圱響を受けず、元のプロセスにあるこずに泚意しおください。
  5. 保存されたコヌルバックの実行は、 #call:



    メ゜ッドの呌び出しが終了したかのように継続したす。
  6. 埩元されたコヌルバックが実行を完了するずすぐに、珟圚の芁求を凊理するフレヌムワヌクコヌドに盎接制埡を返したす送信者を眮き換えたため。
  7. 次に、応答が生成され、適切な゜ケットを介しおブラりザヌに送信されたす。


魔法 私はそれがそのように芋えるず確信しおいたすが、それはうたく機胜したす。 その結果、短い続線があり、新しいプロセスを䜜成する必芁がなく、すべおのフレヌムワヌクコヌドが実行を正垞に完了する機䌚を埗たす。



おわりに



郚分的続線の決定は、珟圚Seasideの開発バヌゞョンに実装されおおり、次のリリヌスに含たれたす。 SqueakずVisualWorksは、すでにコヌドの郚分継続の実装をサポヌトしおいたす。 GemStoneは、VMでの実装をほが完了しおいたす。 郚分継続を実装できない方蚀には、遞択肢がありたす。



これが有甚で興味深い読み物であり、耇雑で理解しやすいず思われるすべおに぀いおのコメントに感謝したす。 ハッピヌシヌサむド。



All Articles