Common IEnumerable <T> and IQueryable <T> in a multi-threaded application

I have little doubt about accessing common IEnumerable and IQueryable in a multi-threaded application.

Consider this piece of code.

 ObservableCollection<SessionFile> files = /* some code */ IEnumerable<Pattern> allFilePatterns= /*some query */ foreach (Pattern pattern in allFilePatterns) { string iclFilePath = Path.Combine(pattern.Location, pattern.Filename); SessionFile sfile = new SessionFile(iclFilePath, pattern.AnalysisDate); SomeDelegate invoker = new SomeDelegate(sfile.SomeHandler); invoker.BeginInvoke(allFilePatterns, null, null); files.Add(sfile ); } 

As you can see, I am using BeginInvoke() , passing the same instance of allFilePatterns each handler named sfile.SomeHandler .

Suppose in SomeHandler I repeat allFilePatterns in a foreach , something like this:

 void SomeHandler(IEnumerable<Pattern> allFilePatterns) { foreach(Pattern pattern in allFilePatterns) { //some code } } 

Now I doubt that: since BeginInvoke() is asynchronous, this means that all foreach in all SomeHandler all files will be executed in parallel (each in its own thread), will the common IEnumerable instance be listed as expected / normal? Is it correct? Can I share the same instance of IEnumerable in multiple threads and list it in parallel?

But what if I use IQueryable instead of IEnumerable in the above code? Any side effect I should know about?

If it is not thread safe, then what should I use?

Note that I use IQueryable for database queries, since I do not want to retrieve all the data from the database. Therefore, I want to avoid IQueryable.ToList() as much as possible.

+4
source share
4 answers

It depends on the implementation. Some implementations of IEnumerable<T> also implement IEnumerator<T> and return from GetEnumerator() . In this case, it is clearly not thread safe ...

As for IQueryable<T> , it also depends on the implementation. For example, Entity Framework contexts are not thread safe and will only work on the thread that created them.

So there is no definite answer to this question ... it will probably work for some implementations, and not for others.

+4
source

I would list ToList() when passing as an argument to the delegate the actual creation of a new set for the stream, with which one could work and avoid problems.

However, I wonder why you would need to have each element of an enumerated enum N times (effectively N ^ 2)? It sounds inefficient.

EDIT: Updated with my intention

+1
source

Well, one thing you could do if working with an IQueryable that is not thread safe (like an Entity Framework query) is to list the results in a single thread, and then pass the results to new threads if necessary.

Then it doesn't matter if IQueryable / IEnumerable is thread safe.

0
source

All Articles