异步执行我的命令 [英] Executing I command asynchronously

查看:90
本文介绍了异步执行我的命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为简单起见,我将Xamarin nUnit测试错误复制为控制台应用程序,它显示了我无法理解的相同问题.因此,首先是有效的代码,其次是无效的代码.

For the sake of simplicity I reproduced my Xamarin nUnit testing error as a console aplication and it shows the same problem that I cannot understand. So first the code that works and second the code that doesn't work.

简单的控制台应用程序

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();
    }
}

这正常工作,控制台将打印正在运行...然后打印在一秒钟内完成的测试.现在,第二个异步版本仅显示正在运行的...

This works fine, the console prints running... then prints test done in one second. Now the second async version which only prints running...

 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))时仅执行部分代码.它只是留下了永不回来的方法.我不明白为什么以及如何解决这个问题.有没有人遇到过同样的问题.谢谢.

So the second case executes only part of the code, when it gets to await Task.Run( () => Thread.Sleep(1000)); it just leaves the method to never come back. I don't understand why and how to solve that. Has anyone ever come across the same problem. Thanks.

推荐答案

主线程在Thread.Sleep(1000);完成之前终止,因此所有子线程也将终止.您可以尝试在Main方法的末尾添加Thread.Sleep(2000);或让它执行其他操作.那就应该可以了.也可以看看

The main thread terminates before Thread.Sleep(1000); has finished and so do all child threads. You can try to add a Thread.Sleep(2000); at the end of your Main method or let it do something else. It should work then. Also have a look at Microsoft's Task class documentation:

等待一个或多个任务完成

由于任务通常在线程池线程上异步运行,因此创建和启动任务的线程会在实例化任务后立即继续执行.在某些情况下,当调用线程是主应用程序线程时,该应用程序可能在任何任务实际开始执行之前终止.在其他情况下,应用程序的逻辑可能要求调用线程仅在一个或多个任务完成执行后才继续执行.您可以通过调用Wait方法来等待一个或多个任务完成,从而使调用线程的执行与其启动的异步任务同步.

Because tasks typically run asynchronously on a thread pool thread, the thread that creates and starts the task continues execution as soon as the task has been instantiated. In some cases, when the calling thread is the main application thread, the app may terminate before any the task actually begins execution. In others, your application's logic may require that the calling thread continue execution only when one or more tasks has completed execution. You can synchronize the execution of the calling thread and the asynchronous tasks it launches by calling a Wait method to wait for one or more tasks to complete.

我希望这会有所帮助.


您最好使用Task.Wait()而不是Thread.Sleep(),因为通常您不知道线程何时完成:


You should better use Task.Wait() instead of Thread.Sleep() because often you don't know when a thread will finish:

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

这不起作用,因为您在RunTest()中启动了一个新线程.然后,在Print()中创建的线程返回并取消阻塞主线程,该主线程返回并终止每个线程.您可以通过在RunTest()中同步运行Thread.Sleep()来解决此问题.一切看起来像这样:

This doesn't work because you start a new thread in RunTest(). Then the thread created in Print() returns and unblocks the main thread which returns and terminates every thread. You could solve this by running Thread.Sleep() in RunTest() synchronously. Everything would look like this:

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();
    }
}

这篇关于异步执行我的命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆