C#异步反序列化方法不会取消

时间:2018-07-30 14:29:18

标签: c# asynchronous cancellation cancellationtokensource

我遇到了以下问题:下面执行的任务异步运行,但是当序列化程序读取内存流时无法取消。当用户发出取消请求(通过按取消按钮)时,将进行取消(从标记中调用方法cancel()),但是任务继续。

服务类别:
从Main类的LoadHelper()调用的异步方法

   public async void StartTask(Action callback, CancellationToken token)
    {
        await Task.Run(callback, token);
    }

主类:

    private void LoadHelper()
    {
        _services.GetInstance<IThreadService>().StartTask(
            () => LoadHelperAsync(), _cancelService.Token);
    }

方法正在异步运行

    private void LoadHelperAsync()
    {
        var serializer = new DataContractSerializer(typeof(UserDatabase));
        string selectedDir;
        ComparisonResult = null;

        _services.GetInstance<IOpenFileService>().DisplayOpenFileDialog(
            "Select a saved comparison",
            "Comparison File(*.xml; *.cmp)|*.xml;*.cmp",
            Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
            out selectedDir);

        if (!string.IsNullOrEmpty(selectedDir))
        {
            _dispatchService.BeginInvoke(() => IsExecuting = true);
            using (FileStream fileStream = new FileStream(selectedDir, FileMode.Open, FileAccess.Read))
            using (DeflateStream compressedStream = new DeflateStream(fileStream, CompressionMode.Decompress))
            using (BufferedStream regularStream = new BufferedStream(fileStream))
            {
                Stream memoryStream;

                //Use filename to determine compression
                if (selectedDir.EndsWith(".cmp", true, null))
                {
                    memoryStream = compressedStream;
                }
                else
                {
                    memoryStream = regularStream;
                }

                Report("Loading comparison");

                Report(0);
                IsExecuting = true;
                ComparisonResult = (UserDatabase)serializer.ReadObject(memoryStream);

                memoryStream.Close();
                fileStream.Close();
                IsExecuting = false;
                Report("Comparison loaded");
            }
            _dispatchService.BeginInvoke(() => IsExecuting = false);
            _dispatchService.BeginInvoke(() => ViewResults.ExecuteIfAble());
        }
        else
        {
            Report("No comparison loaded");
        }

取消代码:

此命令绑定到视图中的“取消”按钮。

     CancelCompare = new Command(o => _cancelService.Cancel(), o => IsExecuting);

来自CancellationService类

    public class CancellationService : ICancellationService, IDisposable
{
    private CancellationTokenSource _tokenSource;

    public CancellationService()
    {
        Reset();
    }

    public CancellationToken Token { get; private set; }

    public void Cancel()
    {
        _tokenSource.Cancel();
    }

    public void Reset()
    {
        _tokenSource = new CancellationTokenSource();
        Token = _tokenSource.Token;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            _tokenSource.Cancel();
            _tokenSource.Dispose();
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

1 个答案:

答案 0 :(得分:2)

调用_tokenSource.Cancel();不会对正在运行的任务做任何事情。取消令牌只有在被取消before Task.Run

后才会中断任务执行

看看:

static void Main(string[] args)
{
    using (var tokenSource = new CancellationTokenSource())
    {
        var aTask = StartTask(() =>
        {
            while (true)
            {
                Console.WriteLine("Nothing is going to happen.");
                // Some long operation
                Thread.Sleep(1000);
            }
        }, tokenSource.Token);

        tokenSource.Cancel();
        aTask.Wait();
    }

    Console.ReadKey();
}

static async Task StartTask(Action callback, CancellationToken cancellationToken)
{
    await Task.Run(callback, cancellationToken);
}

如果要取消执行,则应自己检查取消令牌,没有任何魔术可以为您取消任务:

static void Main(string[] args)
{
    using (var tokenSource = new CancellationTokenSource())
    {
        var aTask = StartTask(cancellationToken =>
        {
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Console.WriteLine("Will stop before that if canceled.");
                // Some long operation
                // Also pass the token all way down
                Task.Delay(1000, cancellationToken).Wait();
            }
        }, tokenSource.Token);

        // Try 0, 500, 1500 to see the difference
        Thread.Sleep(1500);
        tokenSource.Cancel();

        try
        {
            aTask.Wait();
        }
        catch (Exception ex)
        {
            // AggregateException with OperationCanceledException
            Console.WriteLine("Task was canceled.");
            Console.WriteLine(ex.ToString());
        }
    }

    Console.ReadKey();
}

static async Task StartTask(Action<CancellationToken> callback, CancellationToken cancellationToken)
{
    await Task.Run(() => callback(cancellationToken), cancellationToken);
}

请注意,这段代码仅说明了任务的工作方式,从不在生产环境中编写类似的内容。