Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.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
.net 如何完成任务。继续执行<;任务>;(...)_.net_Task Parallel Library - Fatal编程技术网

.net 如何完成任务。继续执行<;任务>;(...)

.net 如何完成任务。继续执行<;任务>;(...),.net,task-parallel-library,.net,Task Parallel Library,我使用HttpClient,我想写一些类似的东西: HttpClient client = ...; Task<string> getContent() { return client.GetAsync(...) .ContinueWith( t => t.Result.Content.ReadAsStringAsync() ); } 但池的一个线程将被阻止。 我想继续做这项工作 我怎样才能做到呢 更新 是的,我确实需要使用Tasks而不是async/await

我使用HttpClient,我想写一些类似的东西:

HttpClient client = ...;
Task<string> getContent()
{
    return client.GetAsync(...)
   .ContinueWith( t => t.Result.Content.ReadAsStringAsync() );
}
但池的一个线程将被阻止。 我想继续做这项工作

我怎样才能做到呢

更新

是的,我确实需要使用Tasks而不是async/await,我真的知道我想要什么

更新2


我修正了我的观点,现在我认为我选择技术是错误的。如果有人怀疑,这里有一个很好的代码。

现在你应该避免
继续使用
,而更喜欢
异步的
/
等待
,除非你有非常具体的原因;我怀疑这会奏效:

异步任务getContent() { var foo=await client.GetAsync(…);//可能带有.ConfigureAwait(false) return await foo.Content.ReadAsStringAsync();//可能带有.ConfigureAwait(false) }
但池的一个线程将被阻止

情况并非如此,因为只有在“antecedent”任务完成后才会调用带
委托的
ContinueWith<代码>结果
不会被阻止,甚至不需要同步

第二个
.Result
ReadAsStringAsync().Result
)正在阻塞。因此,您必须将其转换为另一个
ContinueWith

通常,一个连续的IO序列会变成一个连续的
ContinueWith
序列

一般来说,
wait
在这里更可取,但您表示这不适合您

是的,我确实需要使用Tasks而不是async/await,我真的知道我想要什么

我强烈推荐。我想不出一个好的理由不使用
async
/
await
,除非您被困在.NET 4.0(即Windows XP)上。这不可能,因为您正在使用
HttpClient
Task.Run
。所以请记住,这个答案纯粹是指导性的,不推荐用于生产

ContinueWith
调用可以被“链接”,类似于
Promise。然后
在JavaScript中工作,但开箱即用的C#链接语义比JavaScript更难理解

首先,
任务
类型不会自动展开。有一种
展开方法可用。另一方面,使用
.Result
——一种更自然地与
ContinueWith
一起使用的TPL遗留物——将异常包装在
聚合异常
中,这可能会导致一种有趣的“级联”,您的内部异常会深深地隐藏在嵌套的
聚合异常
实例中。因此出现了
AggregateException.flatte
来纠正事后的混乱。哦,你应该这么做

这里是第一次尝试,明确指定
TaskScheduler
,使用
Unwrap
打开嵌套任务,并通过使用
GetAwaiter().GetResult()
而不是
Result
避免嵌套异常:

Task<string> getContent()
{
  // I am so sorry, future coder, but I cannot use await here because <insert good reason>
  return Task.Run(()=> client.GetAsync(...))
      .ContinueWith(t => t.GetAwaiter().GetResult().Content.ReadAsStringAsync(), TaskScheduler.Default).Unwrap()
      .ContinueWith(t => t.GetAwaiter().GetResult(), TaskScheduler.Default);
}
Task getContent()
{
//我很抱歉,未来的程序员,但我不能在这里使用wait,因为
返回Task.Run(()=>client.GetAsync(…)
.ContinueWith(t=>t.GetAwaiter().GetResult().Content.ReadAsStringAsync(),TaskScheduler.Default).Unwrap()
.ContinueWith(t=>t.GetAwaiter().GetResult(),TaskScheduler.Default);
}

如果您在代码中经常这样做,您可能希望使用封装了一些逻辑的。哦,一定要在评论中写一封道歉信;即使未来的维护者是你自己,这也是处理类似代码的礼貌做法。;)

重要问题:为什么要使用
ContinueWith
?这些天的默认值应该是
wait
it instead不会被阻止,因为
ContinueWith
中的
.Result
将返回已完成的任务。只需使用异步/异步,为什么要使用它呢?不,您不需要使用“任务”而不是“异步/等待”。这些东西一起工作。没有任何东西阻止您编写
async Task getContent(){var response=wait client.GetAsync();return wait response.Content.ReadAsStringAsyng();}
您也可以使用
Task getContent()=>client.GetStringAsync(someUrl)
为什么在
Task.Run中调用
client.GetAsync()
?这是一个异步调用,因此它已经返回了一个
任务
。它不需要包装在
Task.Run()
中。如果没有它,
ContinueWith()
就可以工作。结果将是一个
任务
,需要
展开()
才能完成任务。这不是我问题的答案。@AlexeySubbota这是正确的答案。你必须解释为什么你不想使用它。现在的问题是,不可能给出任何其他答案answer@AlexeySubbota用一个生动的比喻来解释:如果有人说“我的猎枪一直卡在我的脚上,我该怎么解决?”,最正确的答案不是告诉他们如何在保持垂直时取消锁定,而是建议他们远离双脚。问“你为什么要把你的脚打掉?”或许也是合理的,以防有不太可能但真实的原因。所以:如果你有理由瞄准你的脚,我洗耳恭听。在此之前:请将猎枪指向远离身体部位的地方。@MarcGravel不使用async有一些原因。其中之一是取消的可能性。“你会怎么说?”马尔格雷威尔说,这是第二个原因。想象一个长的调用序列,只有最后一个启动异步操作。而且调用方不需要等待完成。我不想将链中的所有函数都标记为异步,因为所有代码都将标记为异步。相反,我只能标记最后一个函数并返回void,但文档中说只能从事件处理程序返回void。我担心会有不好的事情发生。当我想否决我自己的答案的时候。嗯,我想
Task<string> getContent()
{
  // I am so sorry, future coder, but I cannot use await here because <insert good reason>
  return Task.Run(()=> client.GetAsync(...))
      .ContinueWith(t => t.GetAwaiter().GetResult().Content.ReadAsStringAsync(), TaskScheduler.Default).Unwrap()
      .ContinueWith(t => t.GetAwaiter().GetResult(), TaskScheduler.Default);
}