阻止异步任务

时间:2017-02-25 16:54:59

标签: c# asynchronous

我有一个类Reader创建Task并批量读取数据。每次完成阅读批处理时,它都会通过参数中传递的IProgress报告进度。然后我将批处理保存到NoSQL数据库。问题是它有时可以比将批处理保存到数据库更快地报告进度。

我认为如果保存还没有结束,那么一个好的解决方案就是阻止Task。我真的不知道如何实现它。我需要能够通知读取已完成的内容,然后等待保存到db的通知已完成并且可以继续读取。

伪码:

阅读器:

public async Task<bool> ReadAsync(IProgress<Tuple<DataTable, int>> statusCallback) {
    return await Task.Run(() =>
    {
        while(lineCount <= BufferSize) {
         // Read data
        }
    statusCallback.Report(new Tuple<DataTable, int>(data, progress);
    }
}

主要

public Main() {
    var progress = new Progress<Tuple<DataTable, int>>(ReaderStatusCallback);
    reader.ReadAsync(progress);
}

private void ReaderStatusCallback(Tuple<DataTable, int> tuple)
{
    var data = tuple.Item1.ToDocumentData();
    var progress = tuple.Item2;

    _progressBar.Increment(progress);
    _docData.Data = data;
    _repository.Add(_docData);
}

1 个答案:

答案 0 :(得分:0)

这里最简单的解决方案是不使用异步调度更新的IProgress<T>实现。例如:

class BasicProgress<T> : IProgress<T>
{
    private readonly Action<T> _handler;

    public BasicProgress(Action<T> handler)
    {
        _handler = handler;
    }

    private void IProgress<T>.Report(T value)
    {
        _handler(value);
    }
}

然后,对statusCallback.Report()的调用不会返回,直到数据库更新为止。

如果没有更多的背景,就不可能确定什么是最好的。但是,您可能会发现允许数据库更新至少在某种程度上排队的一些价值。在这种情况下,您可以通过仍使用同步IProgress<T>实现修改上述想法,但在ReaderStatusCallback()方法中异步调度更新,并添加计数器以跟踪当前有多少如果该计数器超过某个合理的阈值,则在回调中等待。

现在,所有这一切......似乎你遇到了这个问题,因为你正在阅读一些比数据库本身快得多的源代码。如果是这样,那么为什么任何这些都应该异步完成是值得怀疑的。也许你没有共享的东西可以证明异步方法是合理的,但是根据你到目前为止发布的内容,似乎整个读取和更新数据库逻辑应该只是在一个线程/工人/任务/无论如何。