Use caseA GUI with 2 controls:An input control for text (a DNA sequence) that should be analyzedA result control that displays the analyzing result of the entered textThe analysis takes 2-3 seconds and should start as soon as the text in the input control is changing. The shown result should always match the actual text in the input field.ProblemIf the user types text, it changes multiple times within the processing time of the analysis. Starting multiple processing tasks parallel is not an option.SolutionMy approach for solving the problem above:An 'ItemProcessor' gets the input and process it in background. If a new item was added whereas another item is processing, the new item is 'stored' for subsequent processing.If another item is already stored for subsequent processing, it will be overwritten.The result is returned only, of no item for subsequent processing is available anymore.Implementation:public class LastItemProcessor<TInput, TOutput>{    private readonly Func<TInput, Task<TOutput>> Process;    private readonly Action OnProcessingStartedAction;    private readonly Action OnProcessingFinishedAction;    private readonly Action<Task<TOutput>> OnLastItemProcessedAction;    private TInput myInput;    private bool myIsLastItemFlag = true;    private bool myIsProcessing = false;    private readonly object myLock = new object();    public LastItemProcessor(Func<TInput, Task<TOutput>> process,        Action<Task<TOutput>> onLastItemProcessedAction,        Action onProcessingStartedAction = null,        Action onProcessingFinishedAction = null)    {        process.Ensure(nameof(process)).IsNotNull();        onLastItemProcessedAction.Ensure(nameof(onLastItemProcessedAction)).IsNotNull();        Process = process;        OnProcessingStartedAction = onProcessingStartedAction;        OnProcessingFinishedAction = onProcessingFinishedAction;        OnLastItemProcessedAction = onLastItemProcessedAction;    }    public void ProcessItem(TInput input)    {        lock (myLock)        {            myInput = input;            if (myIsProcessing)            {                myIsLastItemFlag = false;            }            else            {                myIsProcessing = true;                OnProcessingStartedAction?.Invoke();                var task = ProcessNextItemAsync();                task.ContinueWith(t =>                {                    OnLastItemProcessedAction(task);                    OnProcessingFinishedAction?.Invoke();                });            }        }    }    private async Task<TOutput> ProcessNextItemAsync()    {        TOutput result;        try        {            result = await Process(myInput);        }        catch (Exception)        {            // ensure that the processing flag is set in case of exceptions.            myIsProcessing = false;            throw;        }        lock (myLock)        {            if (myIsLastItemFlag)            {                myIsProcessing = false;                return result;            }            myIsLastItemFlag = true;        }        return await ProcessNextItemAsync();    }}Usage// Initialization (in constructor)// Note: AnalyzingError, IsAnalyzing and AnalysisRegions are view model propertiesmyLastItemProcessor = new LastItemProcessor<string, AnalysisRegion[]>(            AnalyzeSequenceAsync,            t =>            {                if (t.IsFaulted)                {                    AnalyzingError = Error Message;                }                else                {                    AnalysisRegions = t.Result;                    AnalyzingError = null;                }            },            () => IsAnalyzing = true,            () => IsAnalyzing = false);// ...// Process item (in setter of Sequence property)myLastItemProcessor.ProcessItem(sequence);I am interested in general code improvements (e.g. naming, simplifications, bugs, ...) and alternative approaches to address that kind of problem.However, any constructive feedback is welcome of course :)
Processing input in background while user is typing
c#;.net;wpf;callback;task parallel library
There are two alternatives:Reactive extensions with Throttle + Switch combo. It will take care of throttling text changes, overriding previous results and scheduling tasks. Rx API is not for the faint-hearted though. See: https://stackoverflow.com/a/22924151/1386995 .TPL Dataflow with BroadcastBlock + ActionBlock combo. It will take care about everything except for throttling. You will have to initialize those blocks with correct buffer sizes and degrees of parallelism. Also note, that Dataflow blocks can be converted to Rx observables with extension methods, so you can combine those frameworks.As for your implementation:if The shown result should always match the actual text in the input  field.Then you should probably cancel incomplete processing when input changes. If you are going to discard the result anyway, then there is no reason to wait for completion. 3s is a lot of time.I don't have a clear understanding on how recursion works with async/await. It can behave differently. Maybe you should take extra precautions to make sure that stack can not overflow.I'm not a fan of my prefixes. But that's a personal preference.myIsLastItemFlag name is a bit confusing. I think something like myIsInputChanged would do a better job at explaining what this flag is for. Also Flag postfix is unnecessary, Is prefix already hints, that it is a bool field.