问题
摘要:将函数 F 并行应用于数组的每个元素,其中 F 不是线程安全的。
我有一组元素 E 要处理,可以说是一个队列。 我想使用相同的函数 f( E ) 并行处理所有这些元素。
现在,理想情况下我可以调用基于map 的并行模式,但该问题具有以下约束。
- 每个元素包含一对 2 个对象。( E = (A,B) )
- 两个元素可以共享一个对象。 ( E1 = (A1,B1); E2 = (A1, B2) )
- 函数 f 不能处理共享一个对象的两个元素。所以 E1 和 E2 不能并行处理。
这样做的正确方法是什么?
我的想法是这样的,
- 琐碎的想法:保留一组事件的 As 和 B,仅当没有其他线程已经在使用 A 或 B 时才开始处理元素。
- 因此,当您将元素提供给线程时,您会将 As 和 B 添加到事件集中。
- 选择第一个元素,如果它的元素不在事件集中产生一个新线程,否则将它推到元素队列的后面。
- 这样做直到队列为空。
- 这会导致死锁吗?理想情况下,当处理结束时,某些元素将变得可用,对吧?
2.-另一个想法是制作这些连接对象的图表。 每个节点代表一个对象 (A/B) 。每个元素都是连接 A 和 B 的边,然后以某种方式处理数据,使我们知道元素永远不会重叠。
问题
- 我们怎样才能做到最好?
- 是否有执行此操作的标准模式?
- 这些方法有问题吗?
- 不是必需的,但如果您能告诉 TBB 方法使用,那就太好了。
最佳答案
“最佳”方法取决于很多因素:
- 你有多少元素“E”,f(E) 需要多少功。 --> 检查并行处理这些元素是否真的值得(如果您需要大量锁定并且没有太多工作要做,您可能会通过并行处理来减慢进程)
- 是否有可能更改使 f(E) 多线程安全的设计?
- 有多少个元素“A”和“B”?元素“E”共享特定版本的 A 和 B 是否存在任何逻辑? --> 如果您可以将元素 E 分类到单独的列表中,其中每个 A 和 B 仅出现在一个列表中,那么您可以并行处理这些列表而无需任何进一步锁定。
- 如果有许多不同的 A 和 B,而您并没有共享太多,您可能想采用一种简单的方法,即在进入时锁定每个“A”和“B”,然后等待直到获得锁。
每当您使用多个锁进行“锁定并等待”时,务必始终以相同的顺序获取锁(例如始终先获取 A,然后获取 B),否则您可能会遇到死锁。这个加锁顺序需要在任何地方都遵守(整个应用程序中的一个地方使用不同的顺序可能会导致死锁)
编辑:此外,如果您执行“尝试锁定”,您需要确保顺序始终相同。否则你可能会导致生命锁:
- 线程 1 锁 A
- 线程2锁B
- 线程 1 试图锁定 B 但失败了
- 线程 2 试图锁定 A 但失败了
- 线程1释放锁A
- 线程2释放锁B
- 转到 1 并重复...
这种情况实际上“无休止”发生的可能性相对较小,但无论如何都应该避免
编辑 2: 主要是我想我只是根据 Ax 将 E(Ax, Bx) 分成不同的列表(例如,共享相同 A 的所有 E 的一个列表)。然后在锁定“B”的同时处理这些列表(如果所需的 B 已被使用,您仍然可以“TryLock”并继续。
关于multithreading - 并行处理 - 连接数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24449001/