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.AnalysisDate);
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.
The major difference between IQueryable and IEnumerable is that IQueryable executes query with filters whereas IEnumerable executes the query first and then it filters the data based on conditions.
So if you working with only in-memory data collection IEnumerable is a good choice but if you want to query data collection which is connected with database `IQueryable is a better choice as it reduces network traffic and uses the power of SQL language.
As MSDN correctly states, "enumerating through a collection is intrinsically not a thread-safe procedure". Even if you use a synchronized collection (or one of the concurrent collections in . NET 4.0), and all methods use a lock statement internally, iteration using foreach may still fail.
They're not thread safe.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With