Функция возвращается до ожидаемого завершения - PullRequest
0 голосов
/ 20 мая 2018

Порядок асинхронных операций ожидания в этом фрагменте кода немного не соответствует.Задача 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 голосов
/ 21 мая 2018

Поскольку DBClient.ScanAsync является не асинхронным / ожидающим методом, а типом обратного вызова асинхронного метода, он будет возвращен сразу после вызова, а результаты - только позже.Чтобы справиться с этим, вы можете использовать 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 и вашкод может обработать его дальше.Это предполагает, что вы не хотите специально запускать остальную часть кода внутри обратного вызова для многопоточности или чего-либо еще и вернетесь к основному потоку кода, чтобы сделать все остальное.Вы также можете выполнить обработку в обратном вызове, если хотите.

...