开发者

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

I've few doubts regarding how shared IEnumerable and IQueryable is accessed in multi-threaded application.

Consider this code snippet.

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.Analys开发者_如何转开发isDate);

   SomeDelegate invoker = new SomeDelegate(sfile.SomeHandler);
   invoker.BeginInvoke(allFilePatterns, null, null);

   files.Add(sfile );
}

As you can see, I'm using BeginInvoke() passing the same instance allFilePatterns to each handler called sfile.SomeHandler.

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

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

Now my doubt is that: since BeginInvoke() is asynchronous, that means all foreach in all SomeHandler of all the files would execute parallelly (each in its own thread), would the shared instance of IEnumerable enumerate as expected/normal? Is this a right approach? Can I share same instance of IEnumerable in multiple threads, and enumerate it parallelly?

And what if I use IQueryable instead of IEnumerable in the above code? Any side-effect that I should be aware of?

If its not thread-safe, then what should I use?

Please note that I'm using IQueryable for database queries, as I don't want to pull all the data from database. Therefore, I want to avoid IQueryable.ToList() as much as possible.


It depends on the implementation. Some implementations of IEnumerable<T> also implement IEnumerator<T>, and return themselves from GetEnumerator(). In that case it's obviously not thread-safe...

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

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


I would ToList() your enumerable when passing as an argument to the delegate to actually create a new set for the thread to work with and avoid problems.

However, I'm wondering why you would need to have each element of the enumerable enumerated N times (effectively N^2)? That sounds inefficient.

EDIT: Updated with my intent


Look at Parallel.For and friends

http://msdn.microsoft.com/en-us/library/dd460693.aspx


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

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜