2016-10-26 22 views
0

私は単純な非同期ボタンと非同期/待機機能を持っています。私のボタンをクリックすると、UIがフリーズします。誰かが私が間違っていることを私に説明することができますか?ブロック非同期/待機ボタンUIブロック

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    LabelCounter.Text = "Running" 
    LabelCounter.Text = await ComputeText() 
End Sub 

と、この機能:

Private Async Function ComputeText() As Task(Of String) 
    Dim result as string = Await Task.Run(Function() 
               'Thread.Sleep(2000) 
               Dim i as Integer = 0 
               While i <> 100000 
                i += 1 
                'block as other staff can access it as well from outside 
                SyncLock thisLock             
                 LabelCounter.Invoke(Sub() 
                       LabelCounter.Text = i 
                      End Sub) 
                End SyncLock 
               End While 

               Return "Done" 
              End Function) 
    Return result 
End Function 
+0

あなたは 'Invoke'を使用しています。これは同期呼び出しです。 – Aybe

+0

まあ、 'Invoke'を何十回も呼び出すのは、おそらくパフォーマンスにとって最善のものではないでしょう。 –

+0

@Glorinああ、なぜそのフリーズUI UI(didntはInvokeが同期であるか知っている)です。しかし、まず、私はこのラベルを更新する必要があります - 私はInvokeを使用する必要があります(私は異なるスレッド上にあるので、私はまた、私はまた、ラベルを更新している他のタスクがあるのでSyncLockを作る必要があります。これは正しいですか?実装する方法は他にありますか? –

答えて

0

私は私のボタンをクリックすると他の人はあなたがAsync/Awaitを使用しているにもかかわらず、指摘してきたように、私のUIの取得が

をフリーズ(これは正しい)、問題はInvokeです。

InvokeはUIスレッドを中断し、何かをするように指示します(この場合はラベルを更新します)。問題は、バックグラウンドスレッドが可能な限り速くUIを中断していることです。

パズルの第2の部分は、が優先度であるということです。 WM_PAINT(つまり、変更が必要な画面の再描画部分)は、「この任意のコードを実行する」メッセージよりも優先順位が低いため、UIは文字どおりリフレッシュする時間がありませんInvoke要求

ラベルを更新してInvokeを直接使用するのではなく、標準IProgress<T>というアプローチを使用して進捗状況を報告することをお勧めします。これは、UIディスプレイをプログラムロジックから分離するという利点があります(Invoke

あなたのロジックをWinFormsに具体的に結び付けるのではなく、フレームワークにとらわれないアプローチ(IProgress<T>)を使用しています。本当の解決策は、背景の更新を抑制することです。バックグラウンドロジック自体でこれを行うことができます(つまり、1000サイクルごとに更新を発行するなど)。これは理想的ではありません。なぜなら、1)ビジネスロジックでUIの問題が解決されているからです。 2)これは、システムの使用状況、CPUのパワーに基づいて、時間の経過とともに変化することができ、など

だから、私は、バックグラウンド・ロジックを持つお勧めします常には)IProgress<T>.Reportを使用して(更新を送信し、IProgress<T>実装はそれらを絞る必要があります。これはRx経由で最も簡単に行えます。 Lee Campbellはblog post on the subject(もっと適切な解決策です)を持っていますが、私はdown-and-dirty git-er-done approach in a gistです(それはもっと適切に更新されていませんが、事前に調整された進捗状況を設定するのは簡単です)。

+0

なぜコードを正常に実行できるのですか? –

+0

@Stephen Cleary it looks Invokeそれを削除しても問題はありません...スティーブンはとても親切で、そのコードを変更して動作させる方法を教えていただけますか?PS同期の代わりに非同期になるInvokeはありますか? –

+0

@JimmyJimm:使用例については、私が投稿した要点を参照してください。WinFormsのための 'BeginInvoke'がありますが、根底にある問題(UIスレッドを叩く100,000の更新)がまだそこに残っているので、助けにはなりません。 –

関連する問題