【发布时间】:2014-04-22 22:13:23
【问题描述】:
这是几个星期以来运行良好的原始代码。在我刚刚进行的测试中,100 次尝试失败了 0 次。
using (var httpClient = new HttpClient())
{
var tasks = new List<Task>();
tasks.Add(httpClient.GetAsync(new Uri("..."))
.ContinueWith(request =>
{
request.Result.Content.ReadAsAsync<IEnumerable<Foo>>()
.ContinueWith(response =>
{
foos = response.Result;
});
}));
tasks.Add(httpClient.GetAsync(new Uri("..."))
.ContinueWith(request =>
{
request.Result.Content.ReadAsAsync<Bar>()
.ContinueWith(response =>
{
bar = response.Result;
});
}));
await Task.WhenAll(tasks);
}
此代码在 100 次尝试中失败了 9 次,其中一个或两个元组值是 null。
var APIresponses = await HttpClientHelper.GetAsync
<
IEnumerable<Foo>,
Bar
>
(
new Uri("..."),
new Uri("...")
);
foos = APIresponses.Item1;
bar = APIresponses.Item2;
private static Task GetAsync<T>(HttpClient httpClient, Uri URI, Action<Task<T>> continuationAction)
{
return httpClient.GetAsync(URI)
.ContinueWith(request =>
{
request.Result.EnsureSuccessStatusCode();
request.Result.Content.ReadAsAsync<T>()
.ContinueWith(continuationAction);
});
}
public static async Task<Tuple<T1, T2>> GetAsync<T1, T2>(Uri URI1, Uri URI2)
{
T1 item1 = default(T1);
T2 item2 = default(T2);
var httpClient = new HttpClient();
var tasks = new List<Task>()
{
GetAsync<T1>(httpClient, URI1, response =>
{
item1 = response.Result;
}),
GetAsync<T2>(httpClient, URI2, response =>
{
item2 = response.Result;
})
};
await Task.WhenAll(tasks);
return Tuple.Create(item1, item2);
}
将代码修改为如下所示,它会再次失败 100 次尝试中的 0 次。
await Task.WhenAll(tasks);
System.Diagnostics.Debug.WriteLine("tasks complete");
System.Diagnostics.Debug.WriteLine(item1);
System.Diagnostics.Debug.WriteLine(item2);
return Tuple.Create(item1, item2);
}
我已经看了半个多小时了,但我看不出错误在哪里。有人看吗?
【问题讨论】:
-
听起来像是某种竞争条件...(对不起,我帮不上忙!)
-
@DaveDev 不用担心,至少你确认了我同事所说的 :)
-
HttpClient不是线程安全的。您是否尝试过为每个请求使用单独的实例? -
@svick 根据MSDN,
GetAsync是线程安全的方法之一。我会看看单独的实例会发生什么。 -
@Stijn 哦,我看了“任何实例成员都不能保证是线程安全的”。部分,并没有注意到线程安全方法的列表。他们本可以更清楚地说明这一点。
标签: c# async-await