c#中同步代码到异步代码的转换
本文关键字:代码 转换 异步 同步 | 更新日期: 2023-09-27 17:49:24
我正在尝试使我的方法变成可以异步调用的东西。
通常从AddQueue方法中,我只会调用WorkingSession类中的ListOfJobsInQueue方法,获得它的结果并完成它。
使用什么信息我可以找到关于异步编程在这里,我已经完成了下面的代码,但它似乎是卡住在CurrentPageCode属性调用。
它甚至没有到达MessageBox。显示"处理完成"+ queueResult。 line.
有没有人可以帮助我,告诉我我错在哪里?
//Primary Class
public void AddQueue()
{
MessageBox.Show(GetJobsFromQueueAsync().Result.Count().ToString());
}
async Task<List<string>> GetJobsFromQueueAsync()
{
Task<List<string>> getJobsTask = WorkingSession.GetlistOfJobsAsync();
List<string> queueResult = await getJobsTask;
MessageBox.Show("Processing complete with " + queueResult.Count + " rows");
return queueResult;
}
//***
//WorkingSession Class
public Task<List<string>> GetlistOfJobsAsync()
{
return Task.Run<List<string>>(() =>
{
return ListOfJobsInQueue();
});
}
public List<string> ListOfJobsInQueue()
{
if (CurrentPageCode == "CS1")
{
List<string> actionList = new List<string>();
short pageNum = PageCurrent;
short pageMax = PageMax;
for (short atPage = pageNum; atPage <= pageMax; atPage++)
{
//Scan each job on the current queue page
for (int lineNum = 5; lineNum < 18; lineNum++)
{
string reference = GetJobText(new Coordinate { row = lineNum });
actionList.Add(reference);
}
//Once finished with this job page, goto the next
SendCMDKey(Mnemonic.F8);
}
return actionList;
}
else
{
return null;
}
}
//Other method / property signatures (for reference)
public string CurrentPageCode;
public bool SendCMDKey(Mnemonic command)
public string GetJobText(Coordinate coordinate)
//***
死锁问题实际上是这个方法:
public void AddQueue()
{
MessageBox.Show(GetJobsFromQueueAsync().Result.Count().ToString());
}
在async
代码中应避免调用Task.Wait
或Task<T>.Result
。我在我的博客上完整地解释了死锁,但总结的版本是await
将捕获上下文(在本例中是UI上下文)并尝试在该上下文(在本例中是UI线程)上恢复其async
方法。对于某些上下文(例如UI上下文),如果你阻塞了该上下文中的线程(例如,在UI线程中调用Task<T>.Result
),那么async
方法无法在该上下文中恢复,从而导致死锁。
要解决这个问题,请使用async
:
public async Task AddQueueAsync()
{
var jobs = await GetJobsFromQueueAsync();
MessageBox.Show(jobs.Count().ToString());
}
这段代码也是不理想的,尽管是以更微妙的方式:
public Task<List<string>> GetlistOfJobsAsync()
{
return Task.Run<List<string>>(() =>
{
return ListOfJobsInQueue();
});
}
通过在Task.Run
中包装整个方法的逻辑,你真正做的是编写一个"假异步"方法。它有一个异步签名,但逻辑只是在后台线程上同步工作。
最好将任何Task.Run
使用尽可能地推到UI层;不要让它出现在任何可重用的库方法中。让你的api告诉你真相:为同步工作提供同步签名。
我能做的最简单的
public async Task<int> GetWorkFlowStageAsync(string tracker,CancellationToken? token = null)
{
return await Task.FromResult(0);
}