在等待任务完成之前返回的函数

时间:2018-05-20 03:38:52

标签: c# async-await amazon-dynamodb

这段代码中async-await操作的顺序有点偏。 await内的DownloadMetasBySortAsync任务行为不符合我的想法。该任务自行完成,但仅在DownloadMetasBySortAsync已将null返回DownloadMetasAsync后才能完成。

我已尝试在Task.Wait() 中添加DownloadMetasAsync以及等待任务的等待任务。我试过了ConfigureAwait()。在完成所需任务之前,DownloadMetasBySortAsync始终会返回null

我错过了什么?

public async Task<List<MyMeta>> DownloadMetasAsync(SortType sortType)
{
    ResetFlags();
    _cloudMetas = await DownloadMetasBySortAsync(sortType);
    Debug.Log((_cloudMetas != null) ? _cloudMetas.Count + " metas downloaded" : "NULL cloudmetas");
    return _cloudMetas;
}

private async Task<List<MyMeta>> DownloadMetasBySortAsync(SortType sortType)
{
    //Load Table
    Table dbTable = null;
    //Can't call LoadTable from main thread
    await Task.Run(() => { 
        try {
            dbTable = Table.LoadTable(DBClient, new TableConfig(_databaseName));
        }catch( Exception ex ) {
            _operationFailed = true;
            ThrowError(ex);
        }
    });
    if(dbTable == null ) { return null; }

    //Set up secondary local index if needed
    string sortIndex = (sortType == SortType.Creator) ? "date-creator-index" : null;

    return await ScanTable(_dbName, sortIndex); //Scan table for list of metas
}

private async Task<List<MyMeta>> ScanTable(string dbName, string index)
{
    List<MyMeta> metaList = null;
    try {
        Dictionary<string,AttributeValue> lastKeyEvaluated = null;

        do {
            var request = new ScanRequest
            {
                TableName = dbName,
                IndexName = index,
                ConsistentRead = true,
                ExclusiveStartKey = lastKeyEvaluated
            };
            Debug.Log("Scanning...");
            await Task.Run(() =>
            {
                DBClient.ScanAsync(request, (responseObj) =>
                {
                    if( responseObj == null ) {
                        Debug.LogWarning("Response NULL");
                    }
                    else {
                        Debug.Log("Response received");
                        if(metaList == null ) { metaList = new List<MyMeta>(); }
                        var resultList = ProcessScanResult(responseObj.Response);
                        if( resultList != null && resultList.Count > 0 ) {
                            metaList.AddRange(resultList);
                        }
                    }
                    lastKeyEvaluated = responseObj.Response.LastEvaluatedKey;
                });
            });

        } while( lastKeyEvaluated != null && lastKeyEvaluated.Count != 0 );
    }
    catch( Exception ex ) {
        ThrowError(ex);
    }

    return metaList;
}

1 个答案:

答案 0 :(得分:1)

由于DBClient.ScanAsync不是async / await方法,而是异步方法的回调类型,因此它将在被调用后立即返回,结果将仅在以后发生。要处理此问题,您可以使用TaskCompletionSource将其变为可以接受的东西:

var task = new TaskCompletionSource<responseObjType>();

DBClient.ScanAsync(request, (responseObj) =>
{
    task.SetResult(responseObj);
}

// Will wait for the callback to be called before continuing and get the results
var responseObj = await task.Task;

if( responseObj == null )
{
    ...

这样,该方法将一直等到调用回调,数据通过TaskCompletionSource对象发回,您的代码可以进一步处理。这假设你并不特别想要在回调中运行其余的代码,用于线程目的或任何东西,并将返回到主代码流来完成剩下的工作。如果需要,您也可以在回调中进行处理。