共享 IEnumerable和IQueryable在多线程应用程序中
我对如何在多线程应用程序中访问共享的 IEnumerable
和 IQueryable
几乎没有疑问。
考虑这个代码片段。
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 );
}
如您所见,我使用 BeginInvoke()
将相同实例 allFilePatterns
传递给每个名为 sfile.SomeHandler
的处理程序代码>.
假设在 SomeHandler
中,我在 foreach
循环中迭代 allFilePatterns,如下所示:
void SomeHandler(IEnumerable<Pattern> allFilePatterns)
{
foreach(Pattern pattern in allFilePatterns)
{
//some code
}
}
现在我的疑问是:因为 BeginInvoke()
是异步的,这意味着所有文件的所有 SomeHandler
中的所有 foreach
都将并行执行(每个都在自己的线程中),的共享实例将并行执行>IEnumerable
按预期/正常枚举?这是正确的做法吗?我可以在多个线程中共享 IEnumerable
的相同实例,并并行枚举它吗?
如果我在上面的代码中使用 IQueryable
而不是 IEnumerable
会怎么样?我应该注意什么副作用?
如果它不是线程安全的,那么我应该使用什么?
请注意,我使用 IQueryable
进行数据库查询,因为我不想从数据库中提取所有数据。因此,我想尽可能避免 IQueryable.ToList()
。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这取决于实施。
IEnumerable
的某些实现还实现IEnumerator
,并从GetEnumerator()
返回自身。在这种情况下,它显然不是线程安全的...至于
IQueryable
,它也取决于实现。例如,实体框架上下文不是线程安全的,只能在创建它们的线程上正常工作。所以这个问题没有唯一的答案......它可能适用于某些实现,但不适用于其他实现。
It depends on the implementation. Some implementations of
IEnumerable<T>
also implementIEnumerator<T>
, and return themselves fromGetEnumerator()
. 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.
当作为参数传递给委托时,我会
ToList()
你的枚举,以实际创建一个新的集合供线程使用并避免问题。但是,我想知道为什么您需要将可枚举的每个元素枚举 N 次(实际上是 N^2)?这听起来效率很低。
编辑:根据我的意图更新
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
查看 Parallel.For 和朋友
http://msdn.microsoft.com/en-us/library/dd460693.aspx
Look at Parallel.For and friends
http://msdn.microsoft.com/en-us/library/dd460693.aspx
好吧,如果使用非线程安全的 IQueryable(如实体框架查询),您可以做的一件事是枚举一个线程中的结果,然后将结果传递给新线程如有必要。
那么 IQueryable/IEnumerable 是否线程安全并不重要。
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.