C#异步HttpWebRequest死锁
几个小时以来,我一直在努力处理C#中的异步代码,我真的不明白为什么我的代码会死锁。 到目前为止,我已经写了很多文章,任何事情都让我感到震惊 希望你能帮助我 下面是我试图运行的代码 主要C#异步HttpWebRequest死锁,c#,asynchronous,async-await,httpwebrequest,C#,Asynchronous,Async Await,Httpwebrequest,几个小时以来,我一直在努力处理C#中的异步代码,我真的不明白为什么我的代码会死锁。 到目前为止,我已经写了很多文章,任何事情都让我感到震惊 希望你能帮助我 下面是我试图运行的代码 主要 Task.Run(异步()=> { 任务事件=getDetailedEvents(); 等待事件发生; }).Wait(); getDetailedEvents: static async Task<EventDetailed[]> getDetailedEvents() {
Task.Run(异步()=>
{
任务事件=getDetailedEvents();
等待事件发生;
}).Wait();
getDetailedEvents:
static async Task<EventDetailed[]> getDetailedEvents()
{
...
EventDetailed[] result = await LoadDetailedEventsDetailsAsync(evnts).ConfigureAwait(false);
return result;
}
静态异步任务getDetailedEvents()
{
...
EventDetailed[]结果=等待LoadDetailedEventsDetailsSync(evnts)。配置等待(false);
返回结果;
}
也是我问题的核心
LoadDetailedEventsDetailsAsync
async static Task<EventDetailed[]> LoadDetailedEventsDetailsAsync(Event[] events)
{
List<EventDetailed> detailed = new List<EventDetailed>();
List<Task<WebResponse>> responses = new List<Task<WebResponse>>();
List<Event> tasksWithStream = new List<Event>();
foreach (Event e in events)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://...");
... some headers etc ...
e.Stream = httpWebRequest.GetRequestStreamAsync();
e.WebRequest = httpWebRequest;
tasksWithStream.Add(e);
}
foreach (var tsk in tasksWithStream)
{
try {
await tsk.Stream.ConfigureAwait(false);
using (var streamWriter = new StreamWriter(tsk.Stream.Result))
{
streamWriter.Write("...");
streamWriter.Flush();
streamWriter.Close();
}
responses.Add(tsk.WebRequest.GetResponseAsync());
}
catch (Exception ex)
{
Logger.mes("Failed to get event data.");
}
}
foreach (var response in responses)
{
try
{
await response.ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.mes("Failed to get event data.");
continue;
}
parseData.Add(ParseData(response));
}
异步静态任务LoadDetailedEventsDetailsAsync(事件[]事件)
{
详细列表=新列表();
列表响应=新列表();
List tasksWithStream=new List();
foreach(事件中的事件e)
{
var httpWebRequest=(httpWebRequest)WebRequest.Create(“http://...");
…一些标题等。。。
e、 Stream=httpWebRequest.GetRequestStreamAsync();
e、 WebRequest=httpWebRequest;
tasksWithStream.Add(e);
}
foreach(tasksWithStream中的var tsk)
{
试一试{
wait tsk.Stream.configurewait(false);
使用(var streamWriter=newstreamwriter(tsk.Stream.Result))
{
streamWriter.Write(“…”);
streamWriter.Flush();
streamWriter.Close();
}
Add(tsk.WebRequest.GetResponseAsync());
}
捕获(例外情况除外)
{
Logger.mes(“未能获取事件数据”);
}
}
foreach(响应中的var响应)
{
尝试
{
等待响应。配置等待(false);
}
捕获(例外情况除外)
{
Logger.mes(“未能获取事件数据”);
继续;
}
Add(parseData(response));
}
几点:
首先,需要注意的是,您几乎不应该调用.Wait
(或.Result
)在异步任务上-您应该使用wait
。控制台应用程序的Main
方法是极少数例外情况之一。原因是如果不阻止主线程,您的程序将过早退出
其次,如果您需要发出多个互不依赖的HTTP请求(即请求B不需要请求A的结果),那么通过并行执行它们可以获得巨大的性能提升。更好的是,每个请求不消耗线程,因为调用是异步的,也就是说,它们在等待响应时不会阻塞线程,因此同一线程可以有效地触发多个并发请求
我不会重新编写您的代码,但我会建议如何重构它:
static void Main(string[] args)
{
// start all async tasks in parallel.
var tasks = GetEvents().Select(GetEventDetailsAsync);
// wait for them all to complete. normally you should use await instead of Wait,
// but you can't because you're in the main method of a console app.
Task.WhenAll(task).Wait();
}
static IEnumerable<Event> GetEvents()
{
// build a list of whatever metadata is needed to do your async work.
// do NOT do any actual async work here.
}
async static Task<EventDetailed> GetEventDetailsAsync(Event e)
{
// do all async work here, use await as needed,
// but only for one event (no loops).
}
static void Main(字符串[]args)
{
//并行启动所有异步任务。
var tasks=GetEvents().Select(GetEventDetailsAsync);
//等待它们全部完成。通常你应该使用wait而不是wait,
//但你不能,因为你是在一个控制台应用程序的主要方法。
Task.WhenAll(Task.Wait();
}
静态IEnumerable GetEvents()
{
//建立一个列表,列出异步工作所需的元数据。
//不要在这里做任何实际的异步工作。
}
异步静态任务GetEventDetailsAsync(事件e)
{
//在此处执行所有异步工作,根据需要使用wait,
//但仅针对一个事件(无循环)。
}
它是什么类型的应用程序?控制台应用程序?WPF?Windows窗体?事件类是什么样的?具体来说,事件流的定义是什么?
?不要等待在getDetailedEvents
上。因为你在状态机上调用等待
,它会死锁。@YacoubMassad:it i声明是公共任务流{get;set;}@FilipEkberg:听起来不错,我会尽快试用!希望到时候我能理解为什么这段代码会死锁。顺便说一句,您建议在第一次调用中删除wait并只使用其结果?
static void Main(string[] args)
{
// start all async tasks in parallel.
var tasks = GetEvents().Select(GetEventDetailsAsync);
// wait for them all to complete. normally you should use await instead of Wait,
// but you can't because you're in the main method of a console app.
Task.WhenAll(task).Wait();
}
static IEnumerable<Event> GetEvents()
{
// build a list of whatever metadata is needed to do your async work.
// do NOT do any actual async work here.
}
async static Task<EventDetailed> GetEventDetailsAsync(Event e)
{
// do all async work here, use await as needed,
// but only for one event (no loops).
}