Accessing values in Task.ContinueWith

时光总嘲笑我的痴心妄想 提交于 2020-01-25 11:59:21

问题


I am starting a task with the following code:

var token = tokenSource.Token;
var taskWithToken = new Task(() =>
        new ProcessMyCommand(_unitOfWork, ..., batchRunId, token).Execute(), 
        token);

In my continue with, I need to know the batchRunId and possibly some other variables listed in the ..., however, it doesn't apepar that this is possible???

taskWithToken.ContinueWith(task =>
        {
            if (!task.IsCanceled)
                return;

            //TODO: make sure no more subsequent runs happen

            //TODO: sync with source data
        }
    );

Is there something I am missing? How can I make sure the .ContinueWith executes with access to the values it needs?


回答1:


First, I'm not even sure if you need continuation in your case. Your code could be simplified into something like:

var taskWithToken = new Task(() =>
    {
        new ProcessMyCommand(_unitOfWork, ..., batchRunId, token).Execute();

        // code from the continuation here
    },
    token);

But if you do want to use ContinueWith() and you're worried about using it because of the ReSharper warning, then you don't have to. Most of the time, code like this is perfectly fine and you can ignore the warning.

Longer version: when you write a lambda that references something from the enclosing scope (so called closure), the compiler has to generate code for that. How exactly does it do that is an implementation detail, but the current compiler generates a single closure class for all closures inside a single method.

What this means in your case is that the compiler generates a class that contains the locals this (because of _unitOfWork), request and batchRunId (and maybe others that you didn't show). This closure object is shared between the new Task lambda and the ContinueWith() lambda, even though the second lambda doesn't use request or this. And as long as the second lambda is referenced from somewhere, those objects can't be garbage collected, even though they can't be accessed from it.

So, this situation can lead to a memory leak, which I believe is why ReSharper is warning you about it. But in almost all cases, this memory leak either doesn't exist (because the second lambda isn't referenced longer than the first one) or it's very small. So, most of the time, you can safely ignore that warning. But if you get mysterious memory leaks, you should investigate the way you're using lambdas and especially places where you get this warning.




回答2:


You can create your MyTaskData class to store your data and result and it may as well store MyTaskData PreviousTaskData property (from previous task) creating linked list of results. Create a Task<MyTaskData> inside which, at the end, you return myNewTaskData;. Then ContinueWith<MyTaskData>(...) inside which you can get previous results through Task.Result property. As for continuation on cancelled Task ContinueWith has a variant with TaskContinuationOptions parameter (MSDN) where you can specify NotOnCanceled



来源:https://stackoverflow.com/questions/16716093/accessing-values-in-task-continuewith

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!