并行处理的dependency injection

我正在尝试练习手动dependency injection(还没有框架)来删除我的代码中的紧耦合。 这只是为了练习 – 我没有考虑具体的实现。

到目前为止,简单的构造函数注入工作正常。

但是当一个类必须在并行循环中使用另一个类时,我无法解决如何解决创建紧耦合的问题。 例:

public class Processor { private IWorker worker; public Processor(IWorker worker) { this.worker = worker; } public List DoStuff() { var list = new List(); for (int i = 0; i < 10; i++) { list.Add(worker.GetString()); } return list; } public List DoStuffInParallel() { var list = new System.Collections.Concurrent.ConcurrentBag(); Parallel.For(0, 10, i => { //is there any trivial way to avoid this?? list.Add(new Worker().GetString()); }); return list.ToList(); } } public class Worker : IWorker { public string GetString() { //pretend this relies on some instance variable, so it not threadsafe return "a string"; } } 

避免在上述情况下并行循环比标准循环慢的明显事实,我怎样才能编写Processor.DoStuffInParallel()方法以避免当前对Worker类的硬依赖?

解决这个问题的一种方法是注入工厂,例如:

 public List DoStuffInParallel(IWorkerFactory factory) { var list = new System.Collections.Concurrent.ConcurrentBag(); Parallel.For(0, 10, i => { list.Add(factory.Create().GetString()); }); return list.ToList(); } 

工厂可能是一个容器拥有的单例,而Create()需要是线程安全的。

请注意,您的任务不能同时改变列表 – 在将工作结果添加到列表时需要同步访问权限 apols,错过了你的ConcurrentBag ) – 为了减少对bag争用,你可能还想用localinit / localFinally查看其中一个Parallel.For重载, 以便在每个任务列表中进行本地的结果聚合。同步到localFinally的聚合/整体包。

编辑
Re:我是否需要为ConcurrentBag注入工厂? IMO,这可以直接创建ConcurrentBag – 它是一个特定于实现的细节,而不是依赖。 例如,单线程实现可能已将其实现为:

 return Enumerable.Range(0, 10) .Select(i => factory.Create().GetString()) .ToList(); 

即没有任何明确的中间容器结构。

您可以选择将方法的接口软化为public IList DoStuffInParallel ,甚至是IEnumerable (最小可能的合同/承诺)。 这里的依赖关系是Worker ,这是你希望能够在unit testing中模拟的。