簡體   English   中英

調試時異步行為同步?

[英]Async behaving sync while debugging?

我對async / await的理解肯定存在缺陷。 我想要一段名為SaveSearchCase的代碼在后台異步運行。

我希望它被解雇並忘記它並繼續使用當前方法的return語句。

public IList<Entities.Case.CreateCaseOutput> createCase(ARC.Donor.Data.Entities.Case.CreateCaseInput CreateCaseInput, ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput)
{
    ..........
    ..........
    ..........
    var AcctLst = rep.ExecuteStoredProcedure<Entities.Case.CreateCaseOutput>(strSPQuery, listParam).ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
    {
        Task<IList<Entities.Case.SaveCaseSearchOutput>> task = saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
        Task t = task.ContinueWith(
                r => { Console.WriteLine(r.Result); }
         );
    }
    Console.WriteLine("After the async call");
    return AcctLst;
}

而SaveCaseSearch看起來像

public async Task<IList<Entities.Case.SaveCaseSearchOutput>> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
    Repository rep = new Repository();
    string strSPQuery = string.Empty;
    List<object> listParam = new List<object>();
    SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key,out strSPQuery, out listParam);
    var AcctLst = await rep.ExecuteStoredProcedureAsync<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam);
    return (System.Collections.Generic.IList<ARC.Donor.Data.Entities.Case.SaveCaseSearchOutput>)AcctLst;
}

但是當我看到調試器createCase方法等待SaveCaseSearch首先完成然后才完成

它打印“After Async Call”

然后返回 我絕對不想要。

那么我的理解哪個方面存在缺陷? 請幫助使其運行異步並繼續使用當前方法的printreturn語句

UPDATE

我更新了SaveCaseSearch方法以反映如下:

public async Task<IList<Entities.Case.SaveCaseSearchOutput>> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
    return Task.Run<IList<Entities.Case.SaveCaseSearchOutput>>(async (SaveCaseSearchInput, case_key) =>
    {
        Repository rep = new Repository();
        string strSPQuery = string.Empty;
        List<object> listParam = new List<object>();
        SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);
        var AcctLst = await rep.ExecuteStoredProcedureAsync<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam);
        return (System.Collections.Generic.IList<ARC.Donor.Data.Entities.Case.SaveCaseSearchOutput>)AcctLst;
    });
}

但是這些參數有問題。 它說

Error   4   A local variable named 'SaveCaseSearchInput' cannot be declared in this scope because it would give a different meaning to 'SaveCaseSearchInput', which is already used in a 'parent or current' scope to denote something else C:\Users\m1034699\Desktop\Stuart_V2_12042016\Stuart Web Service\ARC.Donor.Data\Case\Search.cs   43  79  ARC.Donor.Data

那么這個saveCaseSearch()方法在主線程中同步運行,這是這里的主要問題。 您應該使用操作本身返回Task,而不是使用任務返回結果。 這是一些簡化的例子:

同步運行並等待5秒鍾

    public IList<int> A()
    {

        var AcctLst = new List<int> { 0, 2, 5, 8 };

        if (true)
        {
            Task<IList<int>> task = saveCaseSearch();

            Task t = task.ContinueWith(
                    r => { Console.WriteLine(r.Result[0]); }
             );
        }

        Console.WriteLine("After the async call");

        return AcctLst;
    }

    // runs sync and in the end returns Task that is never actually fired
    public async Task<IList<int>> saveCaseSearch()
    {
        Thread.Sleep(5000);
        return new List<int>() { 10, 12, 16 };
    }

異步運行 - 觸發任務並忘記:

    public IList<int> A()
    {
        ... same code as above
    }

    // notice that we removed `async` keyword here because we just return task.
    public Task<IList<int>> saveCaseSearch()
    {
        return Task.Run<IList<int>>(() =>
        {
            Thread.Sleep(5000);
            return new List<int>() { 10, 12, 16 };
        });
    }

以下是此示例的完整代碼

反對我認為與“即發即忘”相關的所有內容,您可以通過以下方式編寫代碼來實現:

public Task<SaveCaseSearchOutput> SaveCaseSearch(
    SaveCaseSearchInput saveCaseSearchInput,
    long? caseKey)
{
    var rep = new Repository();
    var query = string.Empty;
    var listParam = new List<object>();
    SQL.CaseSQL
       .getSaveCaseSearchParameters(
           saveCaseSearchInput, 
           caseKey, 
           out query,
           out listParam);

    return rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(
        strSPQuery, 
        istParam);
}

然后,如果你想要發射它的地方並在它返回時記錄(這實際上是你所擁有的 - 所以你不會忘記它),這樣做:

public IList<CreateCaseOutput> CreateCase(
    CreateCaseInput createCaseInput,
    SaveCaseSearchInput saveCaseSearchInput)
{
    // Omitted for brevity...

    var AcctLst = 
        rep.ExecuteStoredProcedure<CreateCaseOutput>(
            strSPQuery,
            listParam)
           .ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
    {
        SaveCaseSearch(saveCaseSearchInput,
                       AcctLst.ElementAt(0).o_case_seq)
            .ContinueWith(r => Console.WriteLine(r.Result));
    }

    Console.WriteLine("After the async call");
    return AcctLst;
}

問題是你在SaveSearchCase函數中使用asyncawait ,這基本上意味着你的代碼與“即發即忘”相反。


作為旁注,你應該真正使用asyncawait ,並避免“發射后不管”的想法! 讓您的數據庫調用異步,並利用這個范例來實現它的價值!

考慮以下:

SaveCaseSearch調用可以保持,就像我在上面定義的那樣。

public Task<SaveCaseSearchOutput> SaveCaseSearch(
    SaveCaseSearchInput saveCaseSearchInput,
    long? caseKey)
{
    var rep = new Repository();
    var query = string.Empty;
    var listParam = new List<object>();
    SQL.CaseSQL
       .getSaveCaseSearchParameters(
           saveCaseSearchInput, 
           caseKey, 
           out query,
           out listParam);

    return rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(
        strSPQuery, 
        istParam);
}

然后在你的電話中,改為:

public async Task<IList<CreateCaseOutput>> CreateCase(
    CreateCaseInput createCaseInput,
    SaveCaseSearchInput saveCaseSearchInput)
{
    // Omitted for brevity...

    var AcctLst = 
        await rep.ExecuteStoredProcedureAsync<CreateCaseOutput>(
            strSPQuery,
            listParam)
           .ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
    {
        await SaveCaseSearch(saveCaseSearchInput,
                       AcctLst.ElementAt(0).o_case_seq)
            .ContinueWith(r => Console.WriteLine(r.Result));
    }

    Console.WriteLine("After the async call");
    return AcctLst;
}

這是一個更好的解決方案!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM