等待/异步仍然令人困惑

时间:2020-01-31 21:01:04

标签: c# multithreading asynchronous async-await

我来自Java世界,开始了解C#构造。我仍在努力了解异步/等待的工作方式。 在Stephen Cleary的“异步和等待”一文中,据说要在线程池上运行等待,您需要在该等待上调用ConfigureAwait(false)。那以某种方式与我的经验不符。我已经创建了一个小应用程序,我认为该应用程序无需调用ConfigureAwait在单独的线程上执行awaitable。

我已使用log4net工具进行记录。 在不使用“ ConfigureAwait”方法的情况下,等待对象将在另一个线程([3])上执行,然后调用UI ToolStripButton1_Click(UI线程为[1],池线程为[3] –代码和日志输出附在下面)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public Form1()
    {
        InitializeComponent();
    }

    private async void ToolStripButton1_Click(object sender, EventArgs e)
    {
        await TestAsync();
    }
    private async Task TestAsync()
    {
        log.Info("Button clicked before Run Sleep task. Expect to run this from UI thread");
        Task t = Task.Run( () =>
        {
            log.Info("Button clicked from Run before Sleep. Expect to run this from a pool thread");
            Thread.Sleep(1000 * 5);
            log.Info("Button clicked from Run after Sleep. Expect to run this from a pool thread");
            return true;
        });//.ConfigureAwait(continueOnCapturedContext: false);
        await t;
        log.Info("Button clicked after Run. Expect to run this from UI thread"); // Expect to run this in UI thread
    }
}

}

日志输出如下:

2020-01-31 19:57:14,805 [1]信息WindowsFormsApp1.Form1 [MoveNext]-在“运行睡眠”任务之前单击了按钮。期望从UI线程运行它

2020-01-31 19:57:14,835 [3]信息WindowsFormsApp1.Form1 [b__3_0]-在“睡眠前运行”中单击了按钮。期望从池线程中运行

2020-01-31 19:57:19,837 [3]信息WindowsFormsApp1.Form1 [b__3_0]-在“睡眠后运行”中单击了按钮。期望从池线程中运行

2020-01-31 19:57:19,839 [1]信息WindowsFormsApp1.Form1 [MoveNext]-运行后单击按钮。期望从UI线程运行它

我没有调用ConfigureAwait(false),而是在线程池上执行了awaitable。

我在那里想念什么吗?

1 个答案:

答案 0 :(得分:2)

ConfigureAwait用于继续等待,并在等待完成后继续执行。不是等待的线程池在哪个线程上运行。

因此,await Task.Run()完成后,ConfigureAwait()确定继续操作应在调用上下文还是线程池上运行。

如果将其设置为ConfigureAwait(false),则示例中的结局log.Info将在与前两个​​log.Info相同的线程池上执行

在Stephen Cleary的文章“ Async and Await”中,据说 在您需要调用的线程池上等待运行 在该waitable上的ConfigureAwait(false)。

您没有提供该文章的链接,但如果史蒂芬·克莱里(Stephen Cleary)弄错了,我将感到非常惊讶。