DOBON.NETプログラミング道掲示板

ツリー一括表示

Nomalアイコン 非同期プログラミング時のConsole.WriteLineの動作 /Wan (21/04/11(Sun) 10:41) #34694
Nomalアイコン Re[1]: 非同期プログラミング時のConsole.WriteLineの動作 /Hongliang (21/04/11(Sun) 22:32) #34695
  └Nomalアイコン Re[2]: 非同期プログラミング時のConsole.WriteLineの動作 /Wan (21/04/12(Mon) 10:10) #34696
    ├Nomalアイコン Re[3]: 非同期プログラミング時のConsole.WriteLineの動作 /Wan (21/04/12(Mon) 10:11) #34697 解決み!
    └Nomalアイコン Re[3]: 非同期プログラミング時のConsole.WriteLineの動作 /魔界の仮面弁士 (21/04/12(Mon) 11:02) #34698 解決み!


親記事 / ▼[ 34695 ]
■34694 / 親階層)  非同期プログラミング時のConsole.WriteLineの動作
□投稿者/ Wan 一般人(1回)-(2021/04/11(Sun) 10:41:06)
  • アイコン環境/言語:[VB.net VisualStudio2019] 
    分類:[.NET] 

    下記のコードを複数回実行した結果が次のようになりました。(4回実行した結果)
    1回目結果: End
    2回目結果:2 1 4 5 6 7 8 9 10 3 1 4 End
    3回目結果:5 6 7 8 3 9 2 10 2 End
    4回目結果:7 9 1 4 10 6 3 5 8 1 2 4 3 6 5 7 8 10 9 End

    ※質問です。

    @ 1回目の実行で、08行めのConsoleWrite文が機能しません。なぜですか?

    A 2回目以後では、同じ数値が重複して表示されます。前回の残骸が表示されているように思いますがなぜですか?(キーバッファに残っているから?)

    B 12行目をWriteLineからWriteに変えると、一切表示されなくなります。行終端記号の出力の有無が原因でしょうか?

    C MicroSoftのDocsによるとConsoleクラスは、スレッドセーフとなっていますが、08行目のWrite文が欠落する理由はなんでしょうか?

    非同期プログラムの勉強を始めたばかりで、判らないことばかりなので、あまりにも初歩的な質問で申し訳ありません。
    どなたか?詳しい方いらっしゃいましたら教えてください。
    宜しくお願いいたします。

    01:Private Sub Button1_Click(sender As Object, e As EventArgs)
                       Handles Button1.Click
    02: Dim tasks As New List(Of Task)()
    03: For ctr As Integer = 1 To 10
    04: Dim baseValue As Integer = ctr
    05: tasks.Add(Task.Factory.StartNew(
    06: Sub(b)
    07: Dim i As Integer = CInt(b)
    08: Console.Write("{0} ", i)
    09: End Sub, baseValue))
    10: Next
    11: Dim continuation = Task.WhenAll(tasks)
    12: Console.WriteLine(" End")
    13:End Sub
違反を報告
[ □ Tree ] 返信 削除キー/

▲[ 34694 ] / ▼[ 34696 ]
■34695 / 1階層)  Re[1]: 非同期プログラミング時のConsole.WriteLineの動作
□投稿者/ Hongliang 大御所(599回)-(2021/04/11(Sun) 22:32:11)
  • アイコン
    確認ですが、
    ・アプリケーションのプロジェクトはWindows Formsアプリケーション
    ・デバッグ実行中
    ・Console.Write/WriteLineの出力はViual Studioの出力ウィンドウに出ている
    ということでいいでしょうか。
    
    > B 12行目をWriteLineからWriteに変えると、一切表示されなくなります。
    >     行終端記号の出力の有無が原因でしょうか?
    
    出力ウィンドウへの出力の場合、改行文字が現れない間は出力がバッファリングされます。
    
    > @ 1回目の実行で、08行めのConsoleWrite文が機能しません。なぜですか?
    
    機能はしています。
    ただ、前述のようにバッファリングされているので、まだ出力ウィンドウに表示されていない状態です。
    
    > A 2回目以後では、同じ数値が重複して表示されます。前回の残骸が表示されているように思いますが
    >  なぜですか? (キーバッファに残っているから?)
    
    1の続きになりますが、今回の実行でConsole.WriteLineによって改行文字が現れたため、
    前回までの実行でバッファリングされた状態の文字列が出力されています。
    (キー入力ではないのでキーバッファは関係ないです)
    
    > C MicroSoftのDocsによるとConsoleクラスは、スレッドセーフとなっていますが、
    >  08行目のWrite文が欠落する理由はなんでしょうか?
    
    先述の通り、欠落しているのではなく、後回しにされています。
    
    スレッドを起動するのはいくらかコストがかかるものです。
    なので、Task.Factory.StartNewを呼び出したからといって直ちにその中に書かれた処理が
    開始するわけではありません。
    さて、スレッドを起動中にも元々のスレッドの処理は継続します。
    > Dim continuation = Task.WhenAll(tasks)
    WhenAllメソッドは、「tasksの各処理が全部終わったら、完了状態となるTask」を用意しろという
    メソッドです。なので、WhenAll自体は特に何かを待つわけではありません。
    処理は継続します。
    > Console.WriteLine(" End")
    ここでEndが出力ウィンドウに渡されます。
    
    つまり、1回目のButton1_Clickでは、各Taskが起動しConsole.Writeが呼び出されるよりも先に、
    Console.WriteLineが呼び出されています。
    そのあとでConsole.Writeが順次実行されますが、先述通りこれはバッファリングされ、
    次回以降のButton1_ClickでConsole.WriteLineが行われるまでウィンドウには出てきません。
    
    1回目はEndが真っ先に出力されるのに2回目以降はいくつかその回のConsole.Writeが出力される点については、
    Task.Factory.StartNewが標準で使用するスレッドプールという仕組みに原因を求められますが、
    そこは一旦置いておいてもいいかと思います。
    
    List(Of Task)の全Taskの完了後に特定処理を実行したい場合、Task.WhenAllが返してきたTaskの完了後に
    その処理を実行する必要があります。
    以前はContinueWithを使って記述する必要がありましたが、最近は「Taskの完了後に処理をする」というのを
    手軽に書けるようになりました。
    
    Private Async Sub Button1_Click(略) 略
      ' 途中略
        Await Task.WhenAll(tasks)
        Console.WriteLine(" End")
    End Sub
    
    Asyncは「このメソッド内でAwaitキーワードを使うよ」という宣言です。
    AwaitはTaskに対して使用可能なキーワードで、
    「以降の処理を、Taskが完了した後で実行するように」という意味合いになります。

違反を報告
[ 親 34694 / □ Tree ] 返信 削除キー/

▲[ 34695 ] / ▼[ 34697 ] ▼[ 34698 ]
■34696 / 2階層)  Re[2]: 非同期プログラミング時のConsole.WriteLineの動作
□投稿者/ Wan 一般人(2回)-(2021/04/12(Mon) 10:10:41)
  • アイコンNo34695に返信(Hongliangさんの記事)
    Hongliangさん 
    本当に、多くの時間を割き、丁寧なご回答ありがとうございます。ご指導頂いたことにより、次のような整理ができました。
    @ 仰る通りに出力ウィンドウに表示しています。改行がないと出力されないことを知りませんでした。
    A WhenAllがUIスレッドを止めるもの(WaitAllと勘違い)と捉えていました。
    B 今回の例では、UIスレッドを止めても問題が無かったので、awaitを使うことは考えていませんでしたが、ご指導を頂いて、awaitを使うだけで全てが解決しました。
    C キーバッファとバッファを混同して考えていました。
    D 今回教えて頂いたことにより、WhenAll,WhenAny,WaitAll,WaitAny,awaitなどについての概念が整理できました。
    今回感じたことは、園庭で、多くの幼稚園児が自由に遊んでいるのを監視するような気持で、対応する必要があるなぁ?って思いました。まだまだ、習得の道は長いと思いますが、このように上級者から丁寧な指導を得られることを幸せに感じ頑張ります。
    また、近いうちに、初歩的な質問をすると思いますが、宜しくお願い致します。
    有難うございました。


違反を報告
[ 親 34694 / □ Tree ] 返信 削除キー/

▲[ 34696 ] / 返信無し
■34697 / 3階層)  Re[3]: 非同期プログラミング時のConsole.WriteLineの動作
□投稿者/ Wan 一般人(3回)-(2021/04/12(Mon) 10:11:38)
  • アイコン解決済み
解決み!
違反を報告
[ 親 34694 / □ Tree ] 返信 削除キー/

▲[ 34696 ] / 返信無し
■34698 / 3階層)  Re[3]: 非同期プログラミング時のConsole.WriteLineの動作
□投稿者/ 魔界の仮面弁士 大御所(1329回)-(2021/04/12(Mon) 11:02:12)
  • アイコンNo34696に返信(Wanさんの記事)
    > 仰る通りに出力ウィンドウに表示しています。

    出力先が、イミディエイトや出力ウィンドウでは無くても構わないなら、
    プロジェクトの種類をコンソール アプリケーションに変更すれば、
    Console.Write でも即時出力されるようになります。

    Windows フォーム アプリケーションのままデバッグする場合は、
    Console クラスを使うのではなく、Trace クラスや Debug クラスの
    利用を検討してみてください。

    Trace や Debug であれば改行無しでも即時出力されますし、
    リスナーを差し替えれば、Console やファイル等への出力も可能です。
解決み!
違反を報告
[ 親 34694 / □ Tree ] 返信 削除キー/


Mode/  Pass/


- Child Tree -