首页 \ 问答 \ IO绑定的异步任务不是异步执行的(IO-bound async task not executes asynchronously)

IO绑定的异步任务不是异步执行的(IO-bound async task not executes asynchronously)

我花了很多时间来理解异步编程原理。 但有一点仍不清楚。 我被这段代码搞糊涂了:

    static async Task Method()
    {
        Console.WriteLine($"Method entered.");

        await Task.Delay(1000);
        Console.WriteLine($"Await 1 finished.");

        await Task.Delay(1000);
        Console.WriteLine($"Await 2 finished");
    }

    static int Main(string[] args)
    {
        Console.WriteLine($"Main started.");

        return AsyncContext.Run(() => MainAsync(args));
    }

    static async Task<int> MainAsync(string[] args)
    {
        var t = Method();
        Console.WriteLine("Thread starting sleep.");
        Thread.Sleep(10000);
        Console.WriteLine("Thread stopped sleeping");
        Console.WriteLine(t.IsCompleted ? "Method completed" : "Method not completed");
        await t;
        return 0;
    }

结果:

Main started.
Method entered.
Thread starting sleep.
Thread stopped sleeping
Method not completed
Await 1 finished.
Await 2 finished

据我所知,当主线程处于休眠状态时,应执行来自Method的IO绑定操作(导致Task.Delay模拟IO)并按顺序中断主线程以继续执行方法代码。 所以我希望看到:

Main started.
Method entered.
Thread starting sleep.
Await 1 finished.
Await 2 finished
Thread stopped sleeping
Method completed

我知道通过Thread.Sleep我正在制作停止主线程。 但据我所知,Method()不应该需要线程,因为它包含IO绑定操作。 任何人都能解释我误解的地方吗?

我正在使用的AsynContext是( 这里 )。


I has spend a lot of time to understand async programming principles. But one thing is still unclear. I was confused by this code :

    static async Task Method()
    {
        Console.WriteLine($"Method entered.");

        await Task.Delay(1000);
        Console.WriteLine($"Await 1 finished.");

        await Task.Delay(1000);
        Console.WriteLine($"Await 2 finished");
    }

    static int Main(string[] args)
    {
        Console.WriteLine($"Main started.");

        return AsyncContext.Run(() => MainAsync(args));
    }

    static async Task<int> MainAsync(string[] args)
    {
        var t = Method();
        Console.WriteLine("Thread starting sleep.");
        Thread.Sleep(10000);
        Console.WriteLine("Thread stopped sleeping");
        Console.WriteLine(t.IsCompleted ? "Method completed" : "Method not completed");
        await t;
        return 0;
    }

Result :

Main started.
Method entered.
Thread starting sleep.
Thread stopped sleeping
Method not completed
Await 1 finished.
Await 2 finished

As I understand while Main thread is sleeping IO-bound operations from Method should be executed (cause Task.Delay emulate IO) and interrupt Main thread sequentially to continue execute Method code. So I expect to see:

Main started.
Method entered.
Thread starting sleep.
Await 1 finished.
Await 2 finished
Thread stopped sleeping
Method completed

I know that by Thread.Sleep I am making to stop Main thread. But as I understand Method() should not need thread because it consists of IO-bound operations. Can anybody explain where I am misunderstanding it?

AsynContext that I am using is (here).


原文:https://stackoverflow.com/questions/43469076
更新时间:2023-08-29 12:08

最满意答案

如果你想要串行行为,这应该工作:

    private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
    {
        if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
            return;

        var localIndex = ++_index;

        HttpContext.Current.Response.Write($"starting #{localIndex} <br />");

        Thread.Sleep(1000);
        // or             Task.Delay(1000).Wait();


        HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
    }

或尝试:

    private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
    {
        RegisterAsyncTask(new PageAsyncTask(() => Bob(gridViewRowEventArgs)));
        HttpContext.Current.Response.Write($"b");

    }

    private async Task Bob(GridViewRowEventArgs gridViewRowEventArgs)
    {
        if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
            return;

        var localIndex = ++_index;

        HttpContext.Current.Response.Write($"starting #{localIndex} <br />");

        await Task.Delay(1000);

        HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
    }

If you want serial behaviour, this should work:

    private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
    {
        if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
            return;

        var localIndex = ++_index;

        HttpContext.Current.Response.Write($"starting #{localIndex} <br />");

        Thread.Sleep(1000);
        // or             Task.Delay(1000).Wait();


        HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
    }

or try:

    private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
    {
        RegisterAsyncTask(new PageAsyncTask(() => Bob(gridViewRowEventArgs)));
        HttpContext.Current.Response.Write($"b");

    }

    private async Task Bob(GridViewRowEventArgs gridViewRowEventArgs)
    {
        if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
            return;

        var localIndex = ++_index;

        HttpContext.Current.Response.Write($"starting #{localIndex} <br />");

        await Task.Delay(1000);

        HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
    }

相关问答

更多