在C#中将同步代码转换为异步代码

时间:2014-03-09 23:28:35

标签: c# asynchronous

我正在尝试将我的方法变成可以异步调用的东西。

通常从AddQueue方法中,我只需调用WorkingSession类中的ListOfJobsInQueue方法,得到它的结果并完成它。

在这里使用我能找到的关于异步编程的信息,我已经完成了以下代码,但它似乎停留在 CurrentPageCode 属性调用上。

它甚至没有进入 MessageBox.Show(“Processing with with”+ queueResult.Count +“rows”); 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)

    //***

2 个答案:

答案 0 :(得分:0)

死锁问题实际上是这种方法:

public void AddQueue()
{
    MessageBox.Show(GetJobsFromQueueAsync().Result.Count().ToString());
}

Task.Wait代码中应避免拨打Task<T>.ResultasyncI explain the deadlock in full on my blog,但摘要版本是await将捕获上下文(在本例中为UI上下文)并尝试在该上下文中恢复其async方法(在本例中为UI线程)。对于某些上下文(例如,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中包含整个方法的逻辑,你真正在做的是写一个假的异步&#34;方法。它有一个异步签名,但逻辑只是在后台线程上同步工作。

最好尽可能将Task.Run用于推向UI层;保持它不受任何可重用的库方法的影响。让你的API说实话:拥有同步工作的同步签名。 I have a blog series that goes into detail

答案 1 :(得分:0)

我能做到的最简单

   public async Task<int> GetWorkFlowStageAsync(string tracker,CancellationToken? token = null)
        {
            return await Task.FromResult(0);
        }