Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 学习C&x27;s异步/等待/任务结构;代码挂起等待?_C#_.net_Multithreading_Asynchronous_Async Await - Fatal编程技术网

C# 学习C&x27;s异步/等待/任务结构;代码挂起等待?

C# 学习C&x27;s异步/等待/任务结构;代码挂起等待?,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,为了了解C#的线程构造是如何工作的,我编写了一个简单的测试程序,它执行相同的任务-睡眠3秒钟,然后返回一个对象-同步和异步。我设置了一些秒表,以便更好地了解代码是如何流动的 同步调用按预期工作:“同步前”和“同步后”打印之间有3秒的延迟。但是,对于异步调用,程序在“after async”之后无限期挂起。我希望“异步之前”和“异步之后”能够连续快速打印(因为ExecuteAsync只返回一个任务),然后“等待的异步”会在三秒钟后打印(或者更确切地说,至少是三秒钟后;如果ExecuteAsync之

为了了解C#的线程构造是如何工作的,我编写了一个简单的测试程序,它执行相同的任务-睡眠3秒钟,然后返回一个对象-同步和异步。我设置了一些秒表,以便更好地了解代码是如何流动的

同步调用按预期工作:“同步前”和“同步后”打印之间有3秒的延迟。但是,对于异步调用,程序在“after async”之后无限期挂起。我希望“异步之前”和“异步之后”能够连续快速打印(因为
ExecuteAsync
只返回一个任务),然后“等待的异步”会在三秒钟后打印(或者更确切地说,至少是三秒钟后;如果
ExecuteAsync
之间有大量逻辑,并且当等待该任务时,它可能会更长)

这使我在进行更改的行上出现了一个隐式转换错误:

无法将类型“System.Threading.Tasks.Task”隐式转换为“System.Threading.Tasks.Task”


因为我不熟悉任务、操作等的工作方式,所以我不太确定问题出在哪里/什么不匹配。

您实际上没有运行任何
任务。所以你在等待一些永远不会完成的事情

要按原样修复代码,可以执行以下操作:

private Foo RunExecute(out Task<Foo> task, bool async = false)
{
    Foo outputFoo;

    if(async)
    {
        task = Task.Run(() => makeFoo());
        outputFoo = null;
    }
    else
    {
        task = null;
        outputFoo = makeFoo();
    }

    return outputFoo;
}
为了了解C#的线程构造是如何工作的,我编写了一个简单的测试程序,它执行相同的任务-睡眠3秒钟,然后返回一个对象-同步和异步

您的实际代码相当复杂。让我们从“最简单的”3秒钟同步睡眠开始:

class Program
{
    static void Main(string[] args)
    {
        TestClass tceOn = new TestClass();
        Stopwatch s = Stopwatch.StartNew();
        s.Checkpoint("Before sync on");
        tceOn.Execute();
        s.Checkpoint("After sync on");

        Console.WriteLine("Press any key to end");
        Console.ReadKey();
    }
}

class TestClass
{
    public Foo Execute()
    {
        Thread.Sleep(3000);
        return new Foo();
    }
}

class Foo { }
现在,要创建一个异步等价物,首先从“leaves”(在本例中为
TestClass.Execute中的
Thread.Sleep
)开始,然后逐步执行。这是将代码转换为异步代码的自然方式(在本例中除外,我们将并排而不是就地创建异步代码)。第一步始终是识别阻塞操作(
Thread.Sleep
)并发现异步等价物(在本例中为
Task.Delay
):


关于
ContinueWith
的最后一个问题,答案是“不要使用
ContinueWith
;而是使用
wait

您需要以某种方式运行任务。它不能完全靠自己完成。:)这是
wait
中非常常见的问题。我建议您阅读Stephen Cleary在这方面的优秀著作,特别是Async一路,第二段等等,因为它与您的问题直接相关。除了Kirk Woll的评论之外,Stephen还有,后面谈到了死锁是如何发生的(如您所说)如果代码写得不正确,异步操作可能会发生。我知道这是一种糟糕的形式,但为一个微小的更新写一篇新文章似乎是一种浪费。请您再看一看我的更新,好吗?您的
ContinueWith()
返回一个
Task
,因为lambda有
void
返回类型(即不返回任何内容)。您需要一个返回
Foo
的任务,即
任务
如果要分配给
任务
参数,则
ContinueWith()
必须返回
Foo
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
    Foo outputFoo;

    if(async)
    {
        task = Task.Run(() => makeFoo());
        outputFoo = null;
    }
    else
    {
        task = null;
        outputFoo = makeFoo();
    }

    return outputFoo;
}
private Foo RunExecute(out Task<Foo> task, bool async = false)
{
    Foo outputFoo;

    if(async)
    {
        task = makeFooAsync();
        outputFoo = null;
    }
    else
    {
        task = null;
        outputFoo = makeFoo();
    }

    return outputFoo;
}

async Task<Foo> makeFooAsync()
{
    await Task.Delay(3000);
    return new Foo();
}
private Task<Foo> RunExecute(bool async = false)
{
    Foo outputFoo;

    if(async)
    {
        return makeFooAsync();
    }
    else
    {
        return Task.FromResult(makeFoo());
    }
}
class Program
{
    static void Main(string[] args)
    {
        TestClass tceOn = new TestClass();
        Stopwatch s = Stopwatch.StartNew();
        s.Checkpoint("Before sync on");
        tceOn.Execute();
        s.Checkpoint("After sync on");

        Console.WriteLine("Press any key to end");
        Console.ReadKey();
    }
}

class TestClass
{
    public Foo Execute()
    {
        Thread.Sleep(3000);
        return new Foo();
    }
}

class Foo { }
class TestClass
{
    public async Task<Foo> ExecuteAsync()
    {
        await Task.Delay(3000);
        return new Foo();
    }

    public Foo Execute()
    {
        Thread.Sleep(3000);
        return new Foo();
    }
}
class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
        Console.WriteLine("Press any key to end");
        Console.ReadKey();
    }

    static async Task MainAsync()
    {
        TestClass tceOn = new TestClass();
        Stopwatch s = Stopwatch.StartNew();
        s.Checkpoint("Before sync on");
        tceOn.Execute();
        s.Checkpoint("After sync on");

        s.Checkpoint("Before async on");
        Task<Foo> fooTask = tceOn.ExecuteAsync();
        s.Checkpoint("After async on");

        Foo foo = await fooTask;
        s.Checkpoint("Awaited async on");
    }
}