2015-11-15 14 views
6

たとえば、fooCPUが同期的に実行される(I/Oを実行する純粋な非同期メソッドを呼び出すのではなく、Task.Runまたは同様の方法でコードを実行するために他のスレッドを使用しない)。このメソッドは重い計算を実行します - それはCPUに束縛されています。UIスレッドの特色は何ですか?

今私は、ワーカースレッドによって実行されることを委任せずに、私のプログラムでfooCPUを呼び出します。 fooCPUの1行が実行に時間がかかる場合、終了するまで他の行は実行されません。たとえば、UIスレッドから呼び出すと、UIスレッドがフリーズします(GUIは応答しなくなります)。

async/awaitがmutlithreadingの模倣品であると述べました。 2つの異なるコードの行は、1つのスレッド上で交互に実行されます。これらの行のいずれかが実行に時間がかかる場合、終了するまで他の行は実行されません。

私は、UIスレッドで使用される非同期には当てはまると言われましたが、他のすべてのケース(ASP.NET、スレッドプール上の非同期、コンソールアプリケーションなど)では当てはまりません。

これは何を意味するのですか? UIスレッドはコンソールプログラムのメインスレッドとどのように異なるのですか?

私は誰もこのフォーラムの誰かがコメントなどに出てくるように、関連するトピックの議論を続けることを望んでいないと思いますので、新しい質問をすることをお勧めします。

+0

winformアプリケーションとコンソールアプリケーションで同じコードをコンパイルし、ildasmやリフレクタを使ってコンパイルされたILの違いを確認します。 –

+1

@OguzOzgulこれは多くの問題では役に立ちますが、このコードでは役に立ちません。コードはまったく同じです。どのような変更がグローバルな状態であるか - 同期コンテキストの存在。 – Luaan

+1

答えはかなり良いですが、あなたの好奇心を満足させる唯一のことは、待っていることを詳しく理解することです。 ".net await internals"という検索はかなり良いようです。あなたが一時間を過ごすと、これはすべてに答えるでしょう、私は願っています。 – usr

答えて

10

私はasync intro postを読むことをお勧めします。 asyncawaitのキーワードがどのように機能するかについて説明しています。その後、非同期コードの作成に興味がある場合は、async best practices articleに進みます。イントロポストの

関連部品:

は非同期メソッドの始まりは、他の方法と同様に実行されます。つまり、それは "待つ"(または例外をスローする)ヒットするまで同期的に実行されます。

awaitなし)inner method in your console code exampleが同期実行されていた、なぜこれがあります。

Awaitは、すでに完了しているかどうかを確認することができます。 awaitableがすでに完了している場合、メソッドは(通常のメソッドのように)同期して実行を継続します。

このように、同期していた内部メソッドであるawaitが同期して実行されていたのはこのためです。

その後、待ち時間が完了すると、asyncメソッドの残りの部分が実行されます。待機中の(待ち行列などの)待ち行列を待っている場合、asyncメソッドの残りの部分は、 "待ち状態"が返される前にキャプチャされた "コンテキスト"上で実行されます。それが、その場合には、それはTaskScheduler.Currentで、nullでない限り

この「文脈は」SynchronizationContext.Currentです。または、より簡単なバージョン:

「コンテキスト」とは正確には何ですか? 簡易返答:

  1. あなたがUIスレッドを使用している場合は、UIコンテキストです。
  2. ASP.NETリクエストに応答する場合は、ASP.NETリクエストコンテキストです。
  3. それ以外の場合は、通常はスレッドプールコンテキストです。一緒にこのすべてを置く

、あなたは次のように働いてasync/awaitを視覚化することができます方法は、いくつかの「チャンク」に分割され、各awaitはメソッドが分割された点として作用します。最初のチャンクは常に同期して実行され、各分割ポイントでは同期または非同期のいずれかで続行されます。非同期に続行する場合は、キャプチャされたコンテキストで続行されます(デフォルト)。 UIスレッドは、UIスレッド上の次のチャンクを実行するコンテキストを提供します。

この質問に答えるために、UIスレッドの特殊な点は、待ち行列が同じUIスレッドに戻ってくれるSynchronizationContextを提供することです。

は、私は誰もが、彼らは、インスタンスのコメントに表示されるように、関連するトピックの議論を継続するために、このフォーラムにここに誰も望んでいないと思うので、新しい質問をする方が良いでしょう。

よく、スタックオーバーフローは具体的にはではありません。はフォーラムを意図しています。質問&回答サイトです。だから、網羅的なチュートリアルを求める場所ではない。それはあなたがコードの作業をしようとしているときや、あなたができることすべてを調べた後に何かを理解していないときに来る場所です。これは、SOのコメントが(意図的に)制限されている理由です。短くてすばらしいコードフォーマットなどはありません。このサイトのコメントは、説明やフォーラムのスレッドとしてではなく、説明のためのものです。

+0

ありがとうございます。私は実際にいくつかmsdnのブログとあなたのブログの記事をすでに読んできました。 「UIスレッドは、UIスレッド上で次のチャンクを実行するコンテキストを提供します」 - イントロ・ポストが非同期/待機について言う内容に従わないのですか?コンテキストはスレッドの識別子ではないと思います(多くのスレッドは一つのコンテキストを共有できます)。 _に関して「文脈」はまったく何ですか?簡単な答え:UIスレッドを使用している場合は、UIコンテキストです.'_ _context_が実際に何であるかは説明していません。 – user4205580

+0

「UIスレッドは、UIスレッドの次のチャンクを実行するコンテキストを提供していると思います」というメッセージが表示されます(「https://msdn.microsoft.com/en-us/magazine/gg598924.aspx」) _現在の実装では、UIスレッドごとに1つのWindowsFormsSynchronizationContextが作成されます。 – user4205580

+0

@ user4205580:「簡単な」説明の後の次の段落の紹介記事にあります。「SynchronizationContext.Currentがnullでない場合は、現在のSynchronizationContextです。 (UIとASP.NETの要求コンテキストはSynchronizationContextコンテキストです)。 –

3

はあなたがFoo()は、UIスレッドで呼び出される場合は、その通りだ

async void Foo() { 
    Bar(); 
    await Task.Yield(); 
    Baz(); 
} 

を考えると、その後、Bar()はすぐに呼び出され、そしてBaz()は、いくつかの後の時点で、まだUIスレッドで呼び出されます。

ただし、これはスレッド自体のプロパティではありません。

実際に何が起こっているのは、このメソッドは

Task Foo() { 
    Bar(); 
    return Task.Yield().Continue(() => { 
    Baz(); 
    }); 
} 

に似たものに分割されることをこれは実際には正しくないが、それは間違っている方法は重要ではありません。

私の仮説Continueメソッドに渡される引数は、何らかの方法で呼び出されてタスクによって決定されるコードです。タスクは即座に実行するか、同じスレッドの後の時点で実行するかを決定したり、別のスレッドの後の時点で実行することができます。

実際には、タスクそのものは決まっておらず、代理人をSynchronizationContextに渡すだけです。この同期コンテキストは、実行するコードで何をすべきかを決定します。

これはスレッドの種類によって異なります。 WinFormsコントロールをスレッドからアクセスすると、WinFormsはその特定のスレッドの同期コンテキストをインストールします。これにより、後で実行コードがスケジュールされます同じスレッドで

バックグラウンドスレッドは、すべて異なる同期コンテキストであり、コードのスケジュール方法の変更を引き起こしています。

9

かなりシンプルですが、スレッドは一度に1つしかできません。ですから、UI以外の何かをしている森であなたのUIスレッドを出すと、たとえばdbaseクエリーのように、すべてのUIアクティビティが停止します。これ以上の画面の更新、マウスのクリックやキーの押下に対する応答はありません。外見はフリーズです。

あなたはたぶん「うーん、私はUIをするために別のスレッドを使用します」と言うでしょう。コンソールモードで動作します。しかし、GUIアプリケーションではなく、コードをスレッドセーフにすることは難しく、UIはスレッドセーフではありません。なぜなら、非常に多くのコードが含まれているからです。あなたが書いた種類ではなく、派手なクラスライブラリラッパーで使う種類です。

普遍的な解決策は、それを逆にして、ワーカースレッド上でUI以外のものを行い、UIスレッドを残して、簡単なUIスタッフだけを処理することです。 Async/awaitはあなたがそれを行うのを助け、待っているのはワーカーで実行されます。それを混乱させる唯一の方法は、それは珍しいことではありませんが、にUIスレッドを依頼することです。はあまりにも多くの作業を行います。ミリ秒ごとに1行のテキストをテキストボックスに追加する。それはちょうど悪いUIデザイン、人間はそれを速く読んでいないです。

+0

'私は 'await'自体がスレッドを作成したり切り替えたりしないという多くの答え(ここでは同様に)を読んだと思います。 'await syncFoo()'で同期メソッドを呼び出すと、別のスレッドで実行されません。実際には、 'syncFoo()'と 'await syncFoo()'の間に違いはありません。 – user4205580

+0

もちろん、そうではありません。しかし、彼の正しい考え方の誰も、非同期ではないものを右側に置くことはありません。そして、すべての人がそこに行くわけではなく、誰かが正しい心を得るために最も確実に助けてくれるでしょう。 –

+0

申し訳ありませんが、私は間違っているかもしれませんが、メソッドが非同期であっても、非同期自体はワーカースレッド上で実行されません - そのメソッドが例えば 'Task.Run'を呼び出すかどうかによって異なります。純粋に非同期メソッドは通常、他のスレッドを使用せず、スレッドよりも低いレベルでI/O操作を実行します(http://blog.stephencleary.com/2013/11/there-is-no-thread.html) 。 – user4205580

関連する問題