2016-08-10 3 views
0

WPF MainWindow ctor에서 비정상적인 동작이 있습니다. 비동기 메서드를 사용하여 긴 작업을 만들고 있지만 'DoAsync'라는이 작업이 완료되지 않았습니다! 나는 해결 방법을 발견하지만 난 코드가 두 번 호출하고 결과가 여기 :(실패 이유를 이해하지 않습니다?.net 비동기 비정상 동작

/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    static void WriteToOutput(string message, int increment = 0) 
    { 
     var nw = DateTime.Now; 
     var msg = string.Format("{0}.{1:d3} - thread {2:d1}[0x{3:x4}] |\t{4}{5}", 
            nw.ToString("hh:mm:ss"), 
            nw.Millisecond, 
            System.Threading.Thread.CurrentThread.ManagedThreadId, 
            AppDomain.GetCurrentThreadId(), 
            new string(' ', 4 * increment), 
            message 
           ); 

     System.Diagnostics.Debug.WriteLine(msg); 
    } 

    public async Task DoAsync() 
    { 
     WriteToOutput("DoAsync: begin", 2); 
     await Task.Delay(1);     // enforces asynchronism 
     WriteToOutput("DoAsync: job begin", 3); 
     System.Threading.Thread.Sleep(5000); // simulates some job ;) 
     WriteToOutput("DoAsync: job end", 3); 
     WriteToOutput("DoAsync: end", 2); 
    } 

    private void NormalBehavior() 
    { 
     WriteToOutput("NormalBehavior: begin", 0); 

     Task.Run(async() => 
     { 
      WriteToOutput("NormalBehavior_DoAsync: begin", 1); 
      await DoAsync(); 
      WriteToOutput("NormalBehavior_DoAsync: end", 1); 
     }); 

     WriteToOutput("NormalBehavior: sleeping", 0); 
     System.Threading.Thread.Sleep(10000);  // to see what happens 
     WriteToOutput("NormalBehavior: terminated", 0); 
    } 

    /// <summary> 
    /// Seems the simplest solution, but it fails :(Why ? 
    /// </summary> 
    private void AbnormalBehavior() 
    { 
     WriteToOutput("AbnormalBehavior: begin", 0); 

     WriteToOutput("AbnormalBehavior_DoAsync: begin", 1); 
     var tsk = DoAsync(); 
     WriteToOutput("AbnormalBehavior_DoAsync: end", 1); 

     WriteToOutput("AbnormalBehavior: sleeping", 0); 
     System.Threading.Thread.Sleep(10000);  // to see what happens 
     WriteToOutput("AbnormalBehavior: terminated", 0); 
    } 

    public MainWindow() 
    { 
     NormalBehavior(); 
     // Output: 
     // 05:18:00.833 - thread 8[0x3818] | NormalBehavior: begin 
     // 05:18:00.842 - thread 8[0x3818] | NormalBehavior: sleeping 
     // 05:18:00.846 - thread 9[0x2274] |  NormalBehavior_DoAsync: begin 
     // 05:18:00.848 - thread 9[0x2274] |   DoAsync: begin 
     // 05:18:00.853 - thread 10[0x0778] |    DoAsync: job begin 
     // 05:18:05.855 - thread 10[0x0778] |    DoAsync: job end 
     // 05:18:05.856 - thread 10[0x0778] |   DoAsync: end 
     // 05:18:05.856 - thread 10[0x0778] |  NormalBehavior_DoAsync: end 
     // 05:18:10.843 - thread 8[0x3818] | NormalBehavior: terminated 
     //_________________________________________________________________ 

     AbnormalBehavior(); 
     // Output: 
     // 05:18:10.845 - thread 8[0x3818] | AbnormalBehavior: begin 
     // 05:18:10.846 - thread 8[0x3818] |  AbnormalBehavior_DoAsync: begin 
     // 05:18:10.847 - thread 8[0x3818] |   DoAsync: begin 
     // 05:18:10.849 - thread 8[0x3818] |  AbnormalBehavior_DoAsync: end 
     // 05:18:10.850 - thread 8[0x3818] | AbnormalBehavior: sleeping 
     // 05:18:20.853 - thread 8[0x3818] | AbnormalBehavior: terminated 
     //_________________________________________________________________ 

     InitializeComponent(); 
    } 
} 

누구는 이미이 문제를 발견하거나 설명을 가지고

+0

결과를 요구하지 않으므로. 'var tsk = DoAsync(); tsk.Result'. – cassandrad

답변

1

당신이 그것을 실행할 수 있도록하는 경우 이상, 난 당신이 DoWork의 디버그 창에 "작업 시작"및 기타 메시지를 볼 것으로 예상

async/await에 대한이 예상되는 행동 특히, await는 현재 "컨텍스트"를 캡처합니다 -..하는 "비정상적인"경우는 UI 컨텍스트이며 해당 cont에서 다시 시작됩니다. 내선 나는 내 블로그에 대해 더 자세히 설명해 둔 mechanics of async/await을 설명한다.

이 코드의 다른 점은 Thread.Sleep이 현재 스레드를 차단한다는 것입니다. 특히 UI 스레드에서 Thread.Sleep이 실행되면 해당 스레드가 차단되어 다른 코드를 실행할 수 없습니다.

Task.Run은 UI 컨텍스트가없는 스레드 풀 스레드에서 지정된 코드를 실행하며 해당 경우 await은 스레드 풀 스레드에서 재개됩니다.

따라서 첫 번째 ("작동하는") 예제에서 DoAsync은 스레드 풀 스레드에서 실행되고 5 초 동안 스레드 풀 스레드를 차단합니다. 그동안 NormalBehavior은 UI 스레드를 10 초 동안 차단합니다.

두 번째 (실패한) 예제에서는 AbnormalBehavior이 UI 스레드에서 DoAsync으로 실행됩니다. DoAsyncawait에 도달하면 AbnormalBehavior이 계속 실행되고 10 초 동안 UI 스레드가 차단됩니다. 그래야만 DoAsync이 UI 스레드에서 재개 할 수 있고 5 초 동안 차단할 수 있습니다.

0

스티븐, 'AbnormalBehavior'마지막 잠자기 후 "DoAsync : job begin"& "DoAsync : job end"가 모두 메인 스레드에서 완료되었음을 알 수 있습니다! 사실 모든 작업을 수행하는 동일한 스레드 (주 스레드)이며 자고있는 동안 '작업'을 수행 할 수 없다고 말하면됩니다. 콘솔 프로그램에서 예상했던대로 더 많은 코드가 실행 중입니다! 이 경우에는 작업을 수행하는 다른 스레드 (작업자 스레드)가 있습니다. 아마도 컨텍스트를 캡처 할 필요가 없기 때문일 수 있습니다.

class Program 
{ 
    static DateTime _Start = new DateTime(0); 

    static void WriteToOutput(string message, int increment = 0, bool start = false) 
    { 
     var nw = DateTime.Now; 
     if (start) _Start = nw; 
     var spn = nw - _Start; 

     var msg = string.Format("{0,2:d}.{1:d3} - thread {2,2:d1}[0x{3:x4}] |\t{4}{5}", 
            (int)Math.Floor(spn.TotalSeconds), 
            spn.Milliseconds, 
            System.Threading.Thread.CurrentThread.ManagedThreadId, 
            AppDomain.GetCurrentThreadId(), 
            new string(' ', 4 * increment), 
            message 
           ); 

     if (start) msg = "\n" + msg; 
     //System.Diagnostics.Debug.WriteLine(msg); 
     Console.WriteLine(msg); 
    } 

    public static async Task DoAsync() 
    { 
     WriteToOutput("DoAsync: begin", 2); 
     await Task.Delay(1);     // enforces asynchronism 
     WriteToOutput("DoAsync: job begin", 3); 
     System.Threading.Thread.Sleep(5000); // simulates some job ;) 
     WriteToOutput("DoAsync: job end", 3); 
     WriteToOutput("DoAsync: end", 2); 
    } 

    /// <summary> 
    /// It works correctly but it uses more resources and run more slowly :o 
    /// </summary> 
    /// <returns></returns> 
    public static Task DoRescueAsync() 
    { 
     WriteToOutput("DoAsync: begin", 2); 
     return Task.Run(() => { 
      WriteToOutput("DoAsync: job begin", 3); 
      System.Threading.Thread.Sleep(5000); // simulates some job ;) 
      WriteToOutput("DoAsync: job end", 3); 
      WriteToOutput("DoAsync: end", 2); 
     }); 
    } 

    private static void NormalBehavior() 
    { 
     WriteToOutput("NormalBehavior: begin", 0, true); 

     Task.Run(async() => 
     { 
      WriteToOutput("NormalBehavior_DoAsync: begin", 1); 
      await DoAsync(); 
      WriteToOutput("NormalBehavior_DoAsync: end", 1); 
     }); 

     WriteToOutput("NormalBehavior: sleeping", 0); 
     System.Threading.Thread.Sleep(10000);  // to see what happens 
     WriteToOutput("NormalBehavior: terminated", 0); 
    } 

    /// <summary> 
    /// Seems the simplest solution, but it fails :(Why ? 
    /// </summary> 
    private static void AbnormalBehavior() 
    { 
     WriteToOutput("AbnormalBehavior: begin", 0, true); 

     WriteToOutput("AbnormalBehavior_DoAsync: begin", 1); 
     var tsk = DoAsync(); 
     WriteToOutput("AbnormalBehavior_DoAsync: end", 1); 

     WriteToOutput("AbnormalBehavior: sleeping", 0); 
     System.Threading.Thread.Sleep(10000);  // to see what happens 
     WriteToOutput("AbnormalBehavior: terminated", 0); 
    } 

    static void Main(string[] args) 
    { 
     NormalBehavior(); 
     // Output: 
     // 0.000 - thread 1[0x34cc] | NormalBehavior: begin 
     // 0.014 - thread 1[0x34cc] | NormalBehavior: sleeping 
     // 0.019 - thread 3[0x0bdc] |  NormalBehavior_DoAsync: begin 
     // 0.024 - thread 3[0x0bdc] |   DoAsync: begin 
     // 0.029 - thread 4[0x1568] |    DoAsync: job begin 
     // 5.045 - thread 4[0x1568] |    DoAsync: job end 
     // 5.050 - thread 4[0x1568] |   DoAsync: end 
     // 5.053 - thread 4[0x1568] |  NormalBehavior_DoAsync: end 
     // 10.018 - thread 1[0x34cc] | NormalBehavior: terminated 
     //_________________________________________________________________ 

     AbnormalBehavior();  // now CORRECT as expected ! 
     // Output: 
     // 0.000 - thread 1[0x34cc] | AbnormalBehavior: begin 
     // 0.008 - thread 1[0x34cc] |  AbnormalBehavior_DoAsync: begin 
     // 0.029 - thread 1[0x34cc] |   DoAsync: begin 
     // 0.037 - thread 1[0x34cc] |  AbnormalBehavior_DoAsync: end 
     // 0.043 - thread 1[0x34cc] | AbnormalBehavior: sleeping 
     // 0.047 - thread 3[0x0bdc] |    DoAsync: job begin 
     // 5.062 - thread 3[0x0bdc] |    DoAsync: job end 
     // 7.306 - thread 3[0x0bdc] |   DoAsync: end 
     //10.057 - thread 1[0x34cc] | AbnormalBehavior: terminated 
     //_________________________________________________________________ 

     Console.Write("\nHit a key to close console: "); Console.ReadKey(); 
    } 
}