C# 为什么任务在等待结果之前要等待结果?

C# 为什么任务在等待结果之前要等待结果?,c#,asynchronous,async-await,task-parallel-library,C#,Asynchronous,Async Await,Task Parallel Library,我想了解第三方物流。不幸的是,我无法完成返回类型的任务。根据我所读的内容,我认为将任务分配给变量会异步启动它。当需要返回值时,只需等待它,这确保当前线程等待任务完成 关于以下方面的例子: 没有输出,几秒钟后它立即输出所有内容: I'm writing something while the task is running... 143831542 我做错了什么?在您的代码中 public static int GetIntSync() Getintsync只是一个普通的无聊程序,你在写第一行

我想了解第三方物流。不幸的是,我无法完成返回类型的任务。根据我所读的内容,我认为将任务分配给变量会异步启动它。当需要返回值时,只需等待它,这确保当前线程等待任务完成

关于以下方面的例子:

没有输出,几秒钟后它立即输出所有内容:

I'm writing something while the task is running...
143831542
我做错了什么?

在您的代码中

public static int GetIntSync()
Getintsync只是一个普通的无聊程序,你在写第一行之前就调用了它,所以它完成了所有的工作,然后说,我在做其他事情

该示例之所以有效,是因为调用的函数是异步函数,所以它的设置为

Task<T> something = myAsyncFunc(params)
Now output im going to do something
T result = await myAsyncFunc..
现在结果有了结果做其他事情

这就像建立一个熟食店

第一行基本上是一个deligate,所以不要执行代码。你打我的密码,在等待线上

我的iPad不是最好的地方,但希望能在你的代码中看到你的错误以及如何修复它

public static int GetIntSync()
Getintsync只是一个普通的无聊程序,你在写第一行之前就调用了它,所以它完成了所有的工作,然后说,我在做其他事情

该示例之所以有效,是因为调用的函数是异步函数,所以它的设置为

Task<T> something = myAsyncFunc(params)
Now output im going to do something
T result = await myAsyncFunc..
现在结果有了结果做其他事情

这就像建立一个熟食店

第一行基本上是一个deligate,所以不要执行代码。你打我的密码,在等待线上


我的iPad不是最好的地方,但希望能看到您的错误以及如何修复它。

有几个问题

你不能在这里开始任何异步操作。async await不会自动使事情异步或创建任何线程。阅读

要卸载一些工作,您需要使用Task.Run或Task.Factory.StartNew

您正在使用异步void方法;等待它的完成是不容易的。您应该改用异步任务

因此,您的代码变成:

static Task<int> GetIntAsync()
{
    return Task.Run(()=> GetIntSync());
}

static async Task RunItAsync()
{
    // Should start the task, but should not block
    var task = GetIntAsync();
    Console.WriteLine("I'm writing something while the task is running...");
    // Should wait for the running task to complete and then output the result
    Console.WriteLine(await task);
}
此外,您不需要使用task.start;手动启动任务;;任务。Run已经为您提供了一个已启动的任务


考虑到这两个更改,您的代码应该可以按预期工作

存在两个问题

你不能在这里开始任何异步操作。async await不会自动使事情异步或创建任何线程。阅读

要卸载一些工作,您需要使用Task.Run或Task.Factory.StartNew

您正在使用异步void方法;等待它的完成是不容易的。您应该改用异步任务

因此,您的代码变成:

static Task<int> GetIntAsync()
{
    return Task.Run(()=> GetIntSync());
}

static async Task RunItAsync()
{
    // Should start the task, but should not block
    var task = GetIntAsync();
    Console.WriteLine("I'm writing something while the task is running...");
    // Should wait for the running task to complete and then output the result
    Console.WriteLine(await task);
}
此外,您不需要使用task.start;手动启动任务;;任务。Run已经为您提供了一个已启动的任务

考虑到这两个更改,您的代码应该可以按预期工作

从我读到的内容来看,我认为将任务分配给变量会异步启动它

这是完全错误的

在这里,我有一个任务:做一个三明治。我把它写在一张纸上,放在一个标有“任务”的抽屉里。我开始做三明治了吗?没有

我开始做三明治。开始做三明治会导致我抽屉里出现一张写有任务描述的纸吗?没有

变量和任务之间完全没有关系。无论是什么让你相信他们彼此有关系,现在不要再相信了

当您需要返回值时,只需等待它

确保当前线程等待任务完成

不,如果“等待”是指块

我的理解是:第一个语句应该启动任务

当然,假设TaskOfMethodAsync启动任务并返回启动的任务,这似乎是合理的

紧接着,文本框被追加

然后阻塞线程,直到完成integerTask

绝对不是。等待的全部要点是不要阻塞线程!如果你给我一个任务-做一个三明治-你等着我完成这个任务,你就不会在我给你做三明治的时候睡午觉!你一直在完成工作!否则雇我给你做三明治有什么意义?你想雇佣工人在你做其他事情的时候为你工作,而不是在你睡觉等他们完成的时候

我做错了什么

两件事。首先,您正在将一个void方法变成一个任务,这是非常错误的。异步方法不应该无效,它应该返回一个任务!任务表示异步工作。其次,您只返回已完成的任务

让我们一行一行地看一看它的作用

var task = new Task(RunItAsync);
创建一个任务来表示操作

task.Start();
在线程池上启动任务

然后,主线程在任务完成时阻塞

好的,这个方法是在 e线程池:

static async void RunItAsync() 
{
这个电话有什么用

    var task = GetIntAsync();
那么我们来看看,

static async Task<int> GetIntAsync()
{
   return await Task.FromResult(GetIntSync());
}
这里根本没有异步。这是一种非常非常复杂的编写return GetIntSync的方法—您运行该方法,然后构建两个已完成的任务,而不是一个,而是两个已完成的任务,表示已完成的任务

同样:此方法返回一个任务。此方法的所有子任务都已完成,因此我们只需返回一个具有值的已完成任务

这项任务会发生什么?记得我们在:

var task = GetIntAsync();
这样任务就完成了。这就是任务2

Console.WriteLine("I'm writing something while the task is running...");
不,你在任务完成后写东西。您返回了一个已完成的任务

// Should wait for the running task to complete and then output the result
Console.WriteLine(await task);
否,任务已完成。这将在不等待的情况下提取值并打印它。没有什么可以等待的;任务已经完成了

现在这个方法返回了什么?没有什么这是一种无效的方法。现在我们回来了,完成了该方法的所有工作

接下来会发生什么?传递给原始任务的委托已在工作线程上完成运行,因此在工作线程上运行的任务将完成,并向主线程发出停止等待的信号

从我读到的内容来看,我认为将任务分配给变量会异步启动它

这是完全错误的

在这里,我有一个任务:做一个三明治。我把它写在一张纸上,放在一个标有“任务”的抽屉里。我开始做三明治了吗?没有

我开始做三明治。开始做三明治会导致我抽屉里出现一张写有任务描述的纸吗?没有

变量和任务之间完全没有关系。无论是什么让你相信他们彼此有关系,现在不要再相信了

当您需要返回值时,只需等待它

确保当前线程等待任务完成

不,如果“等待”是指块

我的理解是:第一个语句应该启动任务

当然,假设TaskOfMethodAsync启动任务并返回启动的任务,这似乎是合理的

紧接着,文本框被追加

然后阻塞线程,直到完成integerTask

绝对不是。等待的全部要点是不要阻塞线程!如果你给我一个任务-做一个三明治-你等着我完成这个任务,你就不会在我给你做三明治的时候睡午觉!你一直在完成工作!否则雇我给你做三明治有什么意义?你想雇佣工人在你做其他事情的时候为你工作,而不是在你睡觉等他们完成的时候

我做错了什么

两件事。首先,您正在将一个void方法变成一个任务,这是非常错误的。异步方法不应该无效,它应该返回一个任务!任务表示异步工作。其次,您只返回已完成的任务

让我们一行一行地看一看它的作用

var task = new Task(RunItAsync);
创建一个任务来表示操作

task.Start();
在线程池上启动任务

然后,主线程在任务完成时阻塞

好的,此方法正在线程池上运行:

static async void RunItAsync() 
{
这个电话有什么用

    var task = GetIntAsync();
那么我们来看看,

static async Task<int> GetIntAsync()
{
   return await Task.FromResult(GetIntSync());
}
这里根本没有异步。这是一种非常非常复杂的编写return GetIntSync的方法—您运行该方法,然后构建两个已完成的任务,而不是一个,而是两个已完成的任务,表示已完成的任务

同样:此方法返回一个任务。此方法的所有子任务都已完成,因此我们只需返回一个具有值的已完成任务

这项任务会发生什么?记得我们在:

var task = GetIntAsync();
这样任务就完成了。这就是任务2

Console.WriteLine("I'm writing something while the task is running...");
不,你在任务完成后写东西。您返回了一个已完成的任务

// Should wait for the running task to complete and then output the result
Console.WriteLine(await task);
否,任务已完成。这将在不等待的情况下提取值并打印它。没有什么可以等待的;任务已经完成了

现在这个方法返回了什么?没有什么这是一种无效的方法。现在我们回来了,完成了该方法的所有工作


接下来会发生什么?传递给原始任务的委托已在工作线程上完成运行,因此在工作线程上运行的任务将完成并向主线程发出停止等待的信号。

我在这里看到两个大问题: 第一个是您对的使用:它只不过是包装结果,使其看起来像一个任务,这样您就可以对其使用任务的方法。调用return wait Task.fromResultGettingSync;时;,它:

完全计算GetIntSync, 返回一个整数, 将其传递给FromResult, 立即返回完成的任务, 呼叫等待已完成的任务,因此它会立即继续, 并返回任务。 GetIntAsync根本不是异步的!第二个大问题是,您正在混合测试您的异步/等待技能,该技能也使用Task 使用Task.Run并行执行。异步执行意味着线程的执行顺序不一定与代码顺序同步。您可以尽快在异步方法中执行代码。异步方法可以等待,将控制权返回给它的调用者,直到它表示它准备好再次工作。这样做的目的是使线程保持忙碌,从而使CPU保持忙碌。为了举例说明,让我们使用我最喜欢的机制:隐喻

让逻辑处理器成为桌面工作人员。每次切片,你都会走到一个桌面线程上,上面有一个折叠方法,一个接一个地处理itlines中的表单。如果一行是一种方法,那么您抓取该文件夹,处理其中的表单,然后返回您正在处理的文件夹

然后一张表格X需要你老板的签名。将其交给上司:异步方法Task Task=GetBossToSignForm X是从Worker.WorkDay调用的。然后再处理其他表单。当你得到一个签名的X时,你完成了X,然后继续你原来的状态,一秒钟也不浪费

但是现在你得到了一个表格Y,它要求X已经完成。幸运的是,Worker.WorkDay被标记为async,因此您可以调用wait task来表示:处理此文件夹下的文件夹,直到您看到X返回给您,仍在处理此过程。只有标记为async的文件夹才能由await安全地放置

另一方面,如果您调用task.Wait,则您正在将此桌面标记为off limits锁定线程,直到任务完成。如果您在处理底部文件夹时使用wait,也会发生这种情况。workerprocessor将尝试找到另一个在iTReaded线程上工作的桌面,这可能与您试图简化的实际进程无关

如果您正在调用Task.RunItAsync或创建一个任务,然后启动它,那么您将前往某个空办公桌,并在那里留下一个文件夹RunItAsync。你将在自己的办公桌上工作。最理想的情况是,这项工作可以以两倍的速度完成。如果您是唯一的workerprocessor,这没有任何作用,因为您只需要将轮班时间片分散在两张桌子上工作

那么现在代码的作用是:一个线程在主文件夹所在的桌子A上工作。它抓取文件夹RunItAsync,将其放在空桌子B上,然后将此桌子标记为不可用。工作台B的工作人员可能是也可能不是同一个工作人员,请调用GetIntAsync,然后调用GetIntSync。他自己填写表格,用Task.FromResult将完成的文件夹放在C桌上,然后用wait检查文件夹是否在C桌上。它是!所以等待什么都不做,GetIntAsync返回。完成的任务分配给任务,B打印第一行,检查并查看任务是否已完成,然后打印第二行。文件夹RunItAsync已完成,因此桌面A标记为可用,而桌面B被放弃。一个可能是也可能不是同一个工人的工人走到办公桌A并执行task.Wait之后的任何操作

因此,在您的程序中,没有任何地方两个worker同时工作,也没有任何执行与编写的代码异步执行。 要测试您的异步/等待技能,只需使用现有的异步方法,例如WebClientDownloadStringTaskAsynchttp://stackoverflow.com. 例如:

//Calling asynch method, running on the same thread,
//doing the work as it is eligible for doing.;
Task<string> x = new WebClient().DownloadStringTaskAsync("http://stackoverflow.com");
Console.WriteLine("I'm writing something while the task is running...");
Console.WriteLine("Content of webpage is: {0}", await x);

我在这里看到两个大问题: 第一个是您对的使用:它只不过是包装结果,使其看起来像一个任务,这样您就可以对其使用任务的方法。调用return wait Task.fromResultGettingSync;时;,它:

完全计算GetIntSync, 返回一个整数, 将其传递给FromResult, 立即返回完成的任务, 呼叫等待已完成的任务,因此它会立即继续, 并返回任务。 GetIntAsync根本不是异步的!第二个大问题是,您正在混合测试asynch/await技能(也使用Task)和使用Task.Run的并行执行。异步执行意味着线程的执行顺序不一定与代码顺序同步。您可以尽快在异步方法中执行代码。异步方法可以等待,将控制权返回给它的调用者,直到它表示它准备好再次工作。这样做的目的是使线程保持忙碌,从而使CPU保持忙碌。为了举例说明,让我们使用我最喜欢的机制:隐喻

让逻辑处理器成为桌面工作人员。每次切片,你都会走到一个桌面线程上,上面有一个折叠方法,一个接一个地处理itlines中的表单。如果一行是一种方法,那么您抓取该文件夹,处理其中的表单,然后返回您正在处理的文件夹

然后一张表格X需要你老板的签名。将其交给上司:异步方法Task Task=GetBossToSignForm X是从Worker.WorkDay调用的。然后再处理其他表单。当你得到一个签名的X时,你完成了X,然后继续你原来的状态,一秒钟也不浪费

但是现在你得到了一个表格Y,它要求X已经完成。幸运的是,Worker.WorkDay被标记为asyn c、 因此,您可以调用wait task来表示:处理此文件夹下的文件夹,直到您看到X返回给您,仍在处理此过程。只有标记为async的文件夹才能由await安全地放置

另一方面,如果您调用task.Wait,则您正在将此桌面标记为off limits锁定线程,直到任务完成。如果您在处理底部文件夹时使用wait,也会发生这种情况。workerprocessor将尝试找到另一个在iTReaded线程上工作的桌面,这可能与您试图简化的实际进程无关

如果您正在调用Task.RunItAsync或创建一个任务,然后启动它,那么您将前往某个空办公桌,并在那里留下一个文件夹RunItAsync。你将在自己的办公桌上工作。最理想的情况是,这项工作可以以两倍的速度完成。如果您是唯一的workerprocessor,这没有任何作用,因为您只需要将轮班时间片分散在两张桌子上工作

那么现在代码的作用是:一个线程在主文件夹所在的桌子A上工作。它抓取文件夹RunItAsync,将其放在空桌子B上,然后将此桌子标记为不可用。工作台B的工作人员可能是也可能不是同一个工作人员,请调用GetIntAsync,然后调用GetIntSync。他自己填写表格,用Task.FromResult将完成的文件夹放在C桌上,然后用wait检查文件夹是否在C桌上。它是!所以等待什么都不做,GetIntAsync返回。完成的任务分配给任务,B打印第一行,检查并查看任务是否已完成,然后打印第二行。文件夹RunItAsync已完成,因此桌面A标记为可用,而桌面B被放弃。一个可能是也可能不是同一个工人的工人走到办公桌A并执行task.Wait之后的任何操作

因此,在您的程序中,没有任何地方两个worker同时工作,也没有任何执行与编写的代码异步执行。 要测试您的异步/等待技能,只需使用现有的异步方法,例如WebClientDownloadStringTaskAsynchttp://stackoverflow.com. 例如:

//Calling asynch method, running on the same thread,
//doing the work as it is eligible for doing.;
Task<string> x = new WebClient().DownloadStringTaskAsync("http://stackoverflow.com");
Console.WriteLine("I'm writing something while the task is running...");
Console.WriteLine("Content of webpage is: {0}", await x);

我认为您需要后退一步,更彻底地理解使异步工作所需的所有概念。斯蒂芬·克利里的一系列文章很好地介绍了这一主题。是的,遗憾的是,我学到的大部分东西都错了。这是很棘手的事情。如果你想要一个更技术的,虽然有些过时的介绍,我写了一系列的文章,当我们设计它。从底部开始,这些都是从最新到最新列出的。感谢您的帮助,我将研究它。我认为您需要后退一步,更彻底地理解使异步工作所需的所有概念。斯蒂芬·克利里的一系列文章很好地介绍了这一主题。是的,遗憾的是,我学到的大部分东西都错了。这是很棘手的事情。如果你想要一个更技术的,虽然有些过时的介绍,我写了一系列的文章,当我们设计它。从底部开始,这些是从最新到最新列出的。谢谢你的帮助,我会调查的