提问者:小点点

与决定调用一个函数作为同步方法或任务有关的混乱


我正在学习asyncawait的基础知识,有时不清楚是否应该将方法构建为async

为了把问题弄清楚,我在下面写了两种方法来做同样的事情。在下面的两个示例中,mymethod()由Button1的click事件调用,并执行(推测)相同的操作:

第一道:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }
    
    private int MyMethod()
    {
        int x = 0;
    
        do
        {
            Thread.Sleep(100);
            x++;
    
        } while (x < 10);
    
        return x;
    }
    
    private async void button1_Click(object sender, EventArgs e)
    {
        Task<int> task = new Task<int>(MyMethod);
        task.Start();
    
        int MyNumber = await task;
        label1.Text = MyNumber.ToString();
    
    }
}

第二道:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    private async Task<int> MyMethodAsync()
    {
        int x = 0;

        do
        {
            await Task.Delay(100);
            x++;

        } while (x < 10);

        return x;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        int MyNumber = await MyMethod();

        label1.Text = MyNumber.ToString();
    }
}    

我的困惑是,我该如何在这两种方法中选择?有没有推荐的方式?

作为一个初学者,我的倾向是只有在mymethod()中需要异步任务时,才将mymethod()转换为task。但是我无法得出结论,在其他情况下,将mymethod()作为任务来实现是否很好。

如果第一种方法适用于我们,那么第二种方法(将MyMethod转换为任务)是多余的吗,或者它甚至会产生不良后果?


共2个答案

匿名用户

这取决于你在做什么。

如果您主要是做与IO相关的工作,打开文件,等待网络等,那么第二个例子将是最合适的。这将在主线程上运行任何处理,因此您可以避免线程的开销,而线程的开销大多会被阻塞。

如果您正在进行处理密集型工作,那么第一个示例会更合适。在这种情况下,您不会有任何等待,但您可能仍然希望在后台线程上运行它,以避免阻塞UI。

匿名用户

区别在于第一个示例在后台线程上同步(并阻塞)执行myMethod(),而第二个示例在dispatcher线程上直接执行异步方法,而不阻塞它。

哪一个更好取决于方法的实际操作。通常,对于CPU密集型的工作,您更喜欢后台线程,对于IO相关的工作,例如处理文件或通过网络发送或接收字节时,您更喜欢异步方法。

另请注意,您应该使用task.run启动新任务,而不是使用task构造函数:

Task.Run(MyMethod);