TechFULの中の人

triple-four’s blog

やさC#で簡単な非同期処理3 ~async~

こんにちは!魚介類のサバです。 最近、といっても数か月前ですが、C#の非同期処理が必要になって触った機会があったので、忘れないうちに出力したいと思います!

今回は 「async」 を理解することが目的です。 やっと非同期処理のお話ができます! 親切な解説ができるように努力します!!

※魚介類なので、浅い知識で書いています。ふわふわした解説や、ちょっとした間違いはご了承ください。

非同期な関数

async句を頭につけた関数は、非同期に動くかもしれない関数になり、非同期処理として呼び出すことができます。

int Func() // 同期的に動くメソッド
{
    return 0;
}

async Task<int> FuncAsync() // Funcを非同期に動くかもしれないメソッドに書き換え
{
    return 0; // 実は中身がこのままでは、実質、同期的にしか動きません…
}

void dothis()
{
    FuncAsync(); // 一つ目の非同期処理として呼び出す
    FuncAsync(); // 二つ目の非同期処理として呼び出す
    FuncAsync(); // 三つ目の非同期処理として呼び出す
}
  • また、一般的に戻り値はTask<>型を使用します。<>内にメソッド内で返したい戻り値の型を指定します。

  • C#の非同期な関数は、関数名の後ろにAsyncと付けるのが一般化しているようです。(普通、非同期な関数があれば、同期的に動く関数もあり、コーディング方法も違うため、同期的に動く関数とはっきり見分けがつくようにするためという理由でしょうか?)

  • Taskを戻り値に使用できない場合はvoidを使います。WPFとかがそんな感じです。Taskを戻り値にすることで、非同期処理中の状態や、非同期処理中に起きた例外の処理、非同期処理が終わった後に行いたい処理の記述などができるため、基本的にはTaskを戻り値にしましょう。

  • ここではdothis()を呼び出すと、これを呼び出したスレッドが、3つある、0を返す処理を非同期に処理しなさいと記述したことになります。(実際には0を返すだけの簡単な処理で、小分けに区切る場所もないために同期的に処理されますが…)

非同期処理ってなんぞ?(C#GUIアプリケーションでの話)

非同期処理=並行処理 ( 同期処理=非並行処理 )

非同期処理は、並列処理と似て、複数の処理を一緒に行ってくれます。ただし、使っているスレッドは一つだけで、複数の処理を小分けにローテーションすることで、同時実行しているように見せかかけてくれるものです。並行処理とも言えますね!
非同期処理と、並列処理の違いをしっかり覚えてください!

  • 並列処理 : スレッドを複数個使って、それぞれのスレッドに別々の仕事をしてもらう。各スレッドは同期的に処理をする。
  • 非同期処理(GUI:1つのスレッドを使って、複数の処理を小分けにローテーションすることで、同時に実行しているように見せかける。(並行処理)

同期処理はある処理が完全に終わったら、次の処理を行うという動作で複数の処理を行うことを指します。そのため、同期という言葉を使うのは、一つの処理を何個にも小分けにすることで、他の処理を行う片手間で処理を実行できる点が、同期処理とは異なるからだと考えています。

GUIアプリケーションとCUIアプリケーション

C#は、CUIアプリケーションの場合、非同期処理をスレッドにこだわることなく動的に切り替えて実行するようになります。つまり、その時点で暇にしているスレッドに、非同期処理を順次割り当てていくため、一つのスレッドでローテーションするかもしれませんし、別々のスレッドをたらいまわしするように処理していくのかもしれないということです。これはGUIアプリケーションが、描画用スレッドという特殊なスレッドを持つために、スレッドを区別する必要ができてしまったためです。別段CUIが変態とかGUIが悪いとかそういうわけではありません。

CUIアプリケーションの例

  • VisualStudioの新規プロジェクトにある、「コンソールアプリ」で作られたもの

GUIアプリケーションの例

  • Unity
  • VisualStudioの新規プロジェクトにある、「WPF アプリ」や「Windowsフォームアプリケーション」で作られたもの

まとめ

並列処理

別々のスレッドそれぞれに、仕事を割り当てて実行してもらう。(ここでは小分けにしていないため各スレッドは同期処理。もちろん各スレッドが非同期な場合もある。)

非同期処理(GUI

一つのスレッドに処理を複数個渡し、小分けにしながら、ローテーションして処理する。(並行処理)資源の排他制御などを考えなくていい。 f:id:C_ava:20190310131504p:plain

非同期処理(CUI

複数個ある処理を小分けしたうえで、複数のスレッドで共有しながら、小分けする前の順番を守って処理する。(並行処理をマルチスレッドで分担して処理)動的に処理スレッドへの割り当て方が決まる高度(or汚い? )な並列処理。

非同期処理(GUI+CUI

並行処理。処理を小分けにして実行し、同時に処理を進めているように見せかけることができる。ただし、小分けにした処理の一つが終わらなければそのスレッドはロックされたりするし、小分けにされた処理の進み具合やスレッドが暇にしている度合いによって進み具合が違うため、コードが実行されるタイミングはある程度制御できても基本的に不定

最後に

並列処理非同期処理の違いを理解しましょう!
Task.Run()はマルチスレッド処理(並列処理)で、Asyncは非同期処理(並行処理)です。同じコード内でよく使われるものですが、全くの別物だということを理解してください。

加えて、GUIでの非同期処理(並行処理)と、CUIでの非同期処理をする際の動きを理解しましょう!
またこれらの挙動は、あくまでC#の場合ですので注意してください。

次は Async とセットで出てくる await についての解説です。

運営会社 / サービス

444株式会社

triple-four.com

TechFUL

procon.techful.jp