jon*_*ers 12 .net c# parallel-processing multithreading
我一直在研究.Net 4.0中一些新的并行功能的实用性.
说我有这样的代码:
foreach (var item in myEnumerable)
myDatabase.Insert(item.ConvertToDatabase());
Run Code Online (Sandbox Code Playgroud)
想象一下myDatabase.Insert正在执行一些工作来插入SQL数据库.
从理论上讲,你可以写:
Parallel.ForEach(myEnumerable, item => myDatabase.Insert(item.ConvertToDatabase()));
Run Code Online (Sandbox Code Playgroud)
并自动获得利用多个内核的代码.
但是如果myEnumerable只能通过一个线程进行交互呢?Parallel类是否会通过单个线程进行枚举,并仅将结果分派给循环中的工作线程?
如果myDatabase只能由一个线程进行交互怎么办?在循环的每次迭代中建立数据库连接肯定不会更好.
最后,如果我的"var item"碰巧是UserControl或者必须在UI线程上与之交互的东西呢?
我应该采用什么设计模式来解决这些问题?
在我处理真实世界的应用程序时,切换到Parallel/PLinq/etc并不容易.
Ree*_*sey 12
该IEnumerable<T>接口本质上不是线程安全的. Parallel.ForEach将自动处理此问题,并且只对您枚举中的项目进行并行化.(序列将始终遍历,按顺序遍历一个元素 - 但生成的对象将被并行化.)
如果你的类(即:T)不能由多个线程处理,那么你不应该尝试并行化这个例程.并非每个序列都是并行化的候选者 - 这也是编译器不能自动完成的一个原因;)
如果您正在进行需要使用UI线程的工作,那么这仍然是可能的.但是,您需要在处理后台线程上的用户界面元素时采取相同的谨慎措施,并将数据封送回UI线程.在许多情况下,使用新TaskScheduler.FromCurrentSynchronizationContextAPI 可以简化这一过程.我在这里写了关于这个场景的文章.
所有这些都是合法的问题 - 而PLINQ/TPL并不试图解决这些问题.作为开发人员,编写能够在并行化时正常运行的代码仍然是您的工作.编译器/ TPL/PLINQ可以将多线程不安全的代码转换为线程安全代码,这是不可能的......你必须确保这样做.
对于您描述的某些情况,您应首先确定并行化是否合理.如果瓶颈将获得与数据库的连接或确保正确的操作顺序,那么可能多线程是不合适的.
在TPL如何将可枚举流式传输到多个线程的情况下,您的假设是正确的.序列在单个线程上枚举,然后(可能)将每个工作项分派到要执行的单独线程.该IEnumerable<T>接口本质上不是线程安全的,但是TPL会在幕后为您处理.
PLINQ/TPL可以帮助您做什么,管理何时以及如何将工作分配给多个线程.TPL检测机器上有多个核心,并自动调整用于处理数据的线程数.如果一台机器只有一个CPU /核心,那么TPL可能会选择不并行化工作.开发人员的好处是不必编写两条不同的路径 - 一条用于并行逻辑,一条用于顺序.但是,您仍然有责任确保可以同时从多个线程安全地访问您的代码.
我应该采用什么设计模式来解决这些问题?
这个问题没有一个答案......但是,一般的做法是在对象设计中使用不变性.不可变性使得跨多个线程使用对象更安全,并且是使操作具有可分类性的最常见做法之一.事实上,像F#这样的语言广泛使用不变性来允许语言帮助简化并发编程.
如果您使用的是.NET 4.0,那么您还应该查看ConcurrentXXX集合类System.Collections.Concurrent.在这里您可以找到一些无锁和细粒度的锁定集合结构,这使得编写多线程代码更容易.
| 归档时间: |
|
| 查看次数: |
1680 次 |
| 最近记录: |