并行处理的依赖注入
本文关键字:注入 依赖 并行处理 | 更新日期: 2023-09-27 18:09:28
我正在尝试手工依赖注入(还没有框架)来消除代码中的紧密耦合。这只是为了练习-我没有一个具体的实现在脑海中。
到目前为止,简单的构造函数注入工作得很好。
然而,我不知道如何解决创建一个紧密耦合时,一个类必须使用另一个并行循环。例子:
public class Processor
{
private IWorker worker;
public Processor(IWorker worker)
{
this.worker = worker;
}
public List<string> DoStuff()
{
var list = new List<string>();
for (int i = 0; i < 10; i++)
{
list.Add(worker.GetString());
}
return list;
}
public List<string> DoStuffInParallel()
{
var list = new System.Collections.Concurrent.ConcurrentBag<string>();
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<string> DoStuffInParallel(IWorkerFactory factory)
{
var list = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.For(0, 10, i =>
{
list.Add(factory.Create().GetString());
});
return list.ToList();
}
工厂可以是容器拥有的单例,并且Create()
需要是线程安全的。
ConcurrentBag
)-为了减少bag
上的争用,您可能还希望查看Parallel.For
重载之一,使用localinit/localFinally将结果本地聚合到每个任务列表,然后同步到localFinally
中的聚合/总体包。
编辑
回复:我需要为ConcurrentBag<String>
注入工厂吗?在我看来,直接创建ConcurrentBag
是可以的——它是一个具体的实现细节,而不是一个依赖项。例如,单线程实现可以这样实现:
return Enumerable.Range(0, 10)
.Select(i => factory.Create().GetString())
.ToList();
。没有任何中间容器的显式构造。
您可以选择将方法的接口软化为public IList<string> DoStuffInParallel
甚至IEnumerable<string>
(可能的最小契约/承诺)。这里的依赖关系是在Worker
上,这是您希望能够在单元测试中模拟的。