我使用HttpClient,我想写这样的东西:
HttpClient client = ...;
Task<string> getContent()
{
return client.GetAsync(...)
.ContinueWith( t => t.Result.Content.ReadAsStringAsync() );
}我知道我能写
.ContinueWith( t => t.Result.Content.ReadAsStringAsync().Result);但是池的一个线程会被阻塞。我要continueWithTask和Google任务库一样。
我怎样才能做到呢?
更新
是的,我确实需要使用任务而不是异步/等待,我很清楚我想要什么。
UPDATE2
我修改了我的观点,现在我认为我选择技术是错误的。如果有人怀疑,这里是一个好代码的伟大的例子。
发布于 2019-02-08 08:31:02
现在,您应该避免使用ContinueWith,除非您有非常具体的原因,否则您更倾向于使用async/await;我怀疑这样做会奏效:
async Task<string> getContent()
{
var foo = await client.GetAsync(...); // possibly with .ConfigureAwait(false)
return await foo.Content.ReadAsStringAsync(); // possibly with .ConfigureAwait(false)
}发布于 2019-02-08 15:13:37
是的,我确实需要使用任务而不是异步/等待,我很清楚我想要什么。
我强烈推荐马克的回答。我想不出为什么不使用async/await,除非您被困在Windows4.0(即Windows )上。情况不可能是这样,因为您使用的是HttpClient和Task.Run。因此,请记住,这个答案纯粹是指导性的,不推荐生产。
ContinueWith调用可以是“链式”的,类似于Promise.then在JavaScript中的工作方式,但是开箱即用的C#链接语义比JavaScript的更尴尬。
首先,Task<Task<T>>类型不是自动展开的。有一个可用的Unwrap方法。另一方面,.Result的使用--一种更自然地与ContinueWith一起使用的TPL遗留物--将异常包装在AggregateException中,这可能会导致一种有趣的“级联”,在这种情况下,您的内部异常可以被深入地隐藏在嵌套的AggregateException实例中。因此,AggregateException.Flatten的存在,以纠正后的混乱-事实.哦,你应该去ContinueWith。
这是第一次尝试,显式地指定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);
}如果您在代码中经常这样做,您可能需要使用封装了一些逻辑的.Then。哦,一定要在评论中写个道歉;即使未来的维护者是你自己,这也是与这样的代码相关的礼貌之处。;)
发布于 2019-02-08 12:42:06
但是池的一个线程将被阻塞
情况并非如此,因为只有在“先行”任务完成后才会调用ContinueWith委托。Result不会阻塞,它甚至是免费的同步。
然而,第二个.Result (ReadAsStringAsync().Result)正在阻塞。所以你必须把它变成另一个ContinueWith。
一般来说,一个顺序的IOs序列会变成一个ContinueWith序列。
一般来说,await在这里是可取的,但是您表示这对您不起作用。
https://stackoverflow.com/questions/54588462
复制相似问题