我注意到当我使用HttpClient的单个静态实例时,我的代码挂起,并在几分钟后退出并出现错误 - 只是说其中一个任务被取消而没有给出特定的错误。
static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
try
{
var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t1.Wait();
Console.WriteLine("complete");
var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t2.Wait();
Console.WriteLine("complete");
var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t3.Wait();
Console.WriteLine("complete");
var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t4.Wait();
Console.WriteLine("complete");
Console.ReadKey();
}
catch (System.Exception ex)
{
}
}
当我切换到以下代码并创建HttpClient的单独实例时,问题就消失了。
static void Main(string[] args)
{
try
{
HttpClient client1 = new HttpClient();
var t1 = client1.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t1.Wait();
Console.WriteLine("complete");
HttpClient client2 = new HttpClient();
var t2 = client2.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t2.Wait();
Console.WriteLine("complete");
HttpClient client3 = new HttpClient();
var t3 = client3.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t3.Wait();
Console.WriteLine("complete");
HttpClient client4 = new HttpClient();
var t4 = client4.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
t4.Wait();
Console.WriteLine("complete");
Console.ReadKey();
}
catch (System.Exception ex)
{
}
}
我想知道为什么会发生这种情况,如果有一种方法可以安全地使用静态HttpClient,就像我在第一个代码块中一样(不是必需的,只是出于好奇)
答案 0 :(得分:1)
问题是,你使用" GetStreamAsync"方法。如果您使用一个实例将此方法称为多个,则" _client"打开相同的流多个并将此流复制到" t1"," t2",...您使用此打开的流创建死锁。你应该使用" GetStringAsync"或者你应该在" _client"之前关闭流" t1"打开" t2"等等。以下代码显示了如何执行此操作:
class Program
{
private static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
try
{
using (var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
t1.Wait();
Console.WriteLine("complete");
}
using (var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
t2.Wait();
Console.WriteLine("complete");
}
using (var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
t3.Wait();
Console.WriteLine("complete");
}
using (var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
t4.Wait();
Console.WriteLine("complete");
}
Console.ReadKey();
}
catch (System.Exception ex)
{
}
}
我添加了一个简单的使用,如果程序离开" t1"的使用块,则会自动调用" t1"的处理方法。
此外,我建议您使用" await"用异步代码干净利落地工作。问题是,你不能使用"等待"在你的代码中,是" Main"方法不能用于异步方法。但您可以通过创建一个新的异步void方法来处理这个问题,如下所示:
class Program
{
private static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
GetStreamsAsync();
Console.ReadKey();
}
static async void GetStreamsAsync()
{
try
{
using (var t1 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
Console.WriteLine("complete");
}
using (var t2 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
Console.WriteLine("complete");
}
using (var t3 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
Console.WriteLine("complete");
}
using (var t4 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
{
Console.WriteLine("complete");
}
}
catch (System.Exception ex)
{
}
}
}
你必须调用" Console.ReadKey" " Main"中的方法方法,因为" Main"方法在新的" async void GetSteamsAsync"之前完成。方法
更新(感谢Stuart的评论): 如果您使用其他应用程序模型,建议使用" ConfigureAwait"同样。使用" ConfigureAwait"是没有意义的。在控制台应用程序中,因为没有SynchronizationContext可以捕获并继续。