How to report progress when executing a LINQ expression in a large dataset

If I need to create a fairly large dataset using LINQ, and this may take some time (say, a few seconds), and I need (would like) to generate feedback for use with respect to% 'age done, is there a simple / preferred way to do this?

An example, let's say I have a list A with 1000 cars and a list B with 1000 trucks, and I want to select all possible ordered (automobile, freight) pairs, where car.color == truck.color link to this:

var pairs = from car in A 
            from truck in B 
            where car.color==truck.color 
            select new {car, truck};

Now at some point this will be evaluated as a set of nested foreach loops. I would like to be able to report the percentage of age% as it interacts and ideally updates the progress indicator or something like that.

EDIT: right after my request, I save the result in a member variable as a list like this (which forces the request to be executed):

mPairs = pairs.ToList();

I am doing this because I am doing this in the background workflow, since I do not want the user interface thread to hang when it evaluates the LINQ expression on request in the user interface thread (this is in Silverlight BTW). Therefore, I would like to report on progress. UX is basically:

  • User drags item to workspace
  • Then, the engine starts a background thread to determine (many) the possibilities of connecting to all other elements of the workspace.
  • , , "" ( , , LINQ).
  • (), , (, , , , ).

( )

+3
4

-, , , DataContext, , .

public class ProgressArgs : EventArgs
{
    public ProgressArgs(int count)
    {
        this.Count = count;
    }

    public int Count { get; private set; }
}

public class ProgressContext<T> : IEnumerable<T>
{
    private IEnumerable<T> source;

    public ProgressContext(IEnumerable<T> source)
    {
        this.source = source;
    }

    public event EventHandler<ProgressArgs> UpdateProgress;

    protected virtual void OnUpdateProgress(int count)
    {
        EventHandler<ProgressArgs> handler = this.UpdateProgress;
        if (handler != null)
            handler(this, new ProgressArgs(count));
    }

    public IEnumerator<T> GetEnumerator()
    {
        int count = 0;
        foreach (var item in source)
        {
            // The yield holds execution until the next iteration,
            // so trigger the update event first.
            OnUpdateProgress(++count);
            yield return item;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

var context = new ProgressContext(
    from car in A 
    from truck in B 
    select new {car, truck};
);
context.UpdateProgress += (sender, e) =>
{
    // Do your update here
};

var query = from item in context
            where item.car.color==item.truck.color;

// This will trigger the updates
query.ToArray();

, , . , . , UpdateProgress.

+2

EDIT: , . ...

"no-op" select where, :

public class ProgressCounter
{
    private readonly int total;
    private int count;
    private int lastPercentage;

    public ProgressCounter(int total)
    {
        this.total = total;
    }

    public void Update()
    {
        count++;
        int currentPercentage = (count * 100) / total;
        if (currentPercentage != lastPercentage)
        {
            Console.WriteLine("Done {0}%", currentPercentage);
            lastPercentage = currentPercentage;
        }
        return true;
    }
}

...

var progressCounter = new ProgressCounter(A.Count * B.Count);

var pairs = from car in A
            from truck in B
            where progressCounter.Update()
            where car.color==truck.color
            select new {car, truck};

, . , , , btw:)

MoreLINQ - Pipe, Apply, Via - .

+4

Linq . , , . , "" , .

, progres foreach, . , , , , .

+1
source

Well the mine looked like John, although I am sure that his approach will be much more concise. You can hack something together by the same means.

var pairs = from car in A
            from truck in B
            let myProgress = UpdateProgress(...)
            where car.color == truck.color
            select new { car, truck };

private int UpdateProgress(...)
{
    Console.WriteLine("Updating Progress...");
    return -1;
}

Although the aforementioned request will not be executed until it is repeated. This is also an additional disadvantage of creating a new scope variable inside the query.

0
source

Source: https://habr.com/ru/post/1704918/


All Articles