2017-12-28 39 views
1

간단히하기 위해 Xamarin nUnit 테스트 오류를 ​​콘솔 응용 프로그램으로 재현했으며 이해할 수없는 것과 동일한 문제를 보여줍니다. 먼저 작동하는 코드와 작동하지 않는 코드를 차례로 선택하십시오.I 명령을 비동기로 실행 중

간단한 콘솔 응용 프로그램

public class Working 
{ 

    private MyViewModel _viewModel; 

    public Working() 
    { 
     Console.WriteLine("Start"); 
     _viewModel = new MyViewModel(); 
    } 

    static void Main(string[] args) 
    { 
     Working prog = new Working(); 
     prog.Print(); 

    } 

    public void Print() 
    { 
     _viewModel.NewSurveyCommand.Execute(null); 
    } 
} 

public class MyViewModel 
{ 
    public MyViewModel() 
    { 
     NewSurveyCommand = new MyCommand(RunTest); 
    } 

    public ICommand NewSurveyCommand { get; private set; } 

    private void RunTest() 
    { 
     Console.WriteLine("Running..."); 
     Thread.Sleep(1000); 
     Console.WriteLine("Test done"); 
    } 
} 

public class MyCommand : ICommand 
{ 
    private Action _action; 

    public MyCommand(Action action) 
    { 
     _action = action; 
    } 

    public event EventHandler CanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public void Execute(object parameter) 
    { 
     _action.Invoke(); 
    } 
} 

이 잘 작동이 콘솔 인쇄 실행은 ... 다음 인쇄 테스트는 1 초에 완료. 이제 인쇄 실행 번째 비동기 버전 ...

public class Program 
{ 

    private ViewModel _viewModel; 

    public Program() 
    { 
     Console.WriteLine("Start"); 
     _viewModel = new ViewModel(); 
    } 

    static void Main(string[] args) 
    { 
     Program prog = new Program(); 
     prog.Go(); 

    } 

    async void Go() 
    { 
     await Print(); 
    } 

    public async Task Print() 
    { 
     await Task.Run(() => _viewModel.NewSurveyCommand.Execute(null)); 
    } 
} 

public class ViewModel 
{ 
    public ViewModel() 
    { 
     NewSurveyCommand = new Command(async() => await RunTest()); 
    } 

    public ICommand NewSurveyCommand { get; private set; } 

    public async Task RunTest() 
    { 
     Console.WriteLine("Running..."); 
     await Task.Run(() => Thread.Sleep(1000)); 
     Console.WriteLine("Test done"); 
    } 
} 

public class Command : ICommand 
{ 
    private Action _action; 

    public Command(Action action) 
    { 
     _action = action; 
    } 

    public event EventHandler CanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public void Execute(object parameter) 
    { 
     _action.Invoke(); 
    } 
    } 
} 

그래서 두 번째 경우는 기다린다 Task.Run (() =>에 Thread.sleep (1000)) 오면, 코드의 일부를 실행 ; 방법은 결코 돌아 오지 않을 것입니다. 나는 왜 그리고 어떻게 해결해야하는지 이해하지 못합니다. 누구도 같은 문제를 겪어 본 적이 있습니까? 감사.

+2

가능한 중복 (https://stackoverflow.com/questions/9208921/cant -specify-the-async-modifier-on-the-main-method-of-a-console-app) – mjwills

답변

3

Thread.Sleep(1000);이 끝나기 전에 주 스레드가 종료되고 모든 하위 스레드도 종료됩니다. Main 메서드의 끝에 Thread.Sleep(2000);을 추가하거나 다른 방법으로 처리 할 수 ​​있습니다. 그때 작동합니다.

이 작업은 일반적으로 스레드 풀 스레드에서 비동기 적으로 실행되므로

을 완료하기 위해 하나 이상의 작업 대기, 작성하고 작업을 즉시 실행을 계속 시작하는 스레드 : 또한 Microsoft's Task class documentation를 보라 작업이 인스턴스화되었으므로 경우에 따라 호출 스레드가 기본 응용 프로그램 스레드 일 때 응용 프로그램이 실제로 작업을 시작하기 전에 종료 될 수 있습니다. 다른 응용 프로그램의 논리에서는 하나 이상의 작업이 실행을 완료 한 경우에만 호출 스레드가 실행을 계속해야 할 수도 있습니다. 하나 이상의 작업이 완료 될 때까지 대기하는 Wait 메서드를 호출하여 호출 스레드와 실행되는 비동기 작업의 실행을 동기화 할 수 있습니다.

이 정보가 도움이되기를 바랍니다.

편집 :

static void Main(string[] args) 
{ 
    Program prog = new Program(); 
    Task t = prog.Print(); 
    t.Wait(); 
} 

이되지 않습니다
당신은 더 나은 대신에 Thread.sleep()의 자주 스레드가 완료됩니다 때 모르기 때문에) Task.Wait를 (사용해야합니다 RunTest()에서 새 스레드를 시작하기 때문에 작동합니다. 그런 다음 Print()에서 생성 된 스레드는 모든 스레드를 반환하고 종료하는 주 스레드를 반환하고 차단 해제합니다. RunTest()에서 Thread.Sleep()을 동 기적으로 실행하여 문제를 해결할 수 있습니다. 모든 것이 같을 것이다 :

public class Program 
{ 

    private ViewModel _viewModel; 

    public Program() 
    { 
     Console.WriteLine("Start"); 
     _viewModel = new ViewModel(); 
    } 

    static void Main(string[] args) 
    { 
     Program prog = new Program(); 
     Task t = prog.Print(); 
     t.Wait(); 
    } 

    async void Go() 
    { 
     await Print(); 
    } 

    public async Task Print() 
    { 
     await Task.Run(() => _viewModel.NewSurveyCommand.Execute(null)); 
    } 
} 

public class ViewModel 
{ 
    public ViewModel() 
    { 
     NewSurveyCommand = new Command(() => RunTest()); 
    } 

    public ICommand NewSurveyCommand { get; private set; } 

    public void RunTest() 
    { 
     Console.WriteLine("Running..."); 
     Thread.Sleep(1000); 
     Console.WriteLine("Test done"); 
    } 
} 

public class Command : ICommand 
{ 
    private Action _action; 

    public Command(Action action) 
    { 
     _action = action; 
    } 

    public event EventHandler CanExecuteChanged; 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public void Execute(object parameter) 
    { 
     _action.Invoke(); 
    } 
} 
[콘솔 응용 프로그램의 '홈페이지'방식의 '비동기'변경을 지정할 수 없습니다]의
+0

예 !!!! 주 스레드에 Thread.Sleep을 넣 자마자 다시 돌아와서 Main에서 튀어 나오지 않았습니다. –