Ste*_*eve 5 c# dependency-injection task-parallel-library
我正在尝试练习手动依赖注入(还没有框架)来删除我的代码中的紧耦合.这只是为了练习 - 我没有考虑具体的实现.
到目前为止,简单的构造函数注入工作正常.
但是,当一个类必须在并行循环中使用另一个类时,我无法弄清楚如何解决创建紧耦合问题.例:
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";
}
}
Run Code Online (Sandbox Code Playgroud)
避免在上述情况下并行循环比标准循环慢的明显事实,我怎样才能编写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();
}
Run Code Online (Sandbox Code Playgroud)
工厂可以是容器拥有的单例,并且Create()需要是线程安全的。
当然请注意,您的任务不能同时改变列表 - 将工作结果添加到列表时您需要同步访问(apols,错过了您的ConcurrentBag)- 为了减少 上的争用bag,您可能还想查看localinit / localFinallyParallel.For的重载之一,以便在同步到聚合 / 之前将结果本地聚合到每个任务列表中整体包里的。localFinally
编辑
回复:我需要注入一个工厂吗ConcurrentBag<String>?IMO,直接创建就可以了ConcurrentBag- 它是一个特定于实现的细节,而不是依赖项。例如,单线程实现可能已将其实现为:
return Enumerable.Range(0, 10)
.Select(i => factory.Create().GetString())
.ToList();
Run Code Online (Sandbox Code Playgroud)
即没有任何显式构造的中间容器。
您可以选择软化方法的接口,public IList<string> DoStuffInParallel甚至软化到IEnumerable<string>(尽可能小的合同/承诺)。这里的依赖项是Worker,这是您希望能够在单元测试中模拟的内容。
| 归档时间: |
|
| 查看次数: |
979 次 |
| 最近记录: |