并行处理的依赖注入

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类的硬依赖?

Stu*_*tLC 4

解耦的一种方法是注入工厂,例如:

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,这是您希望能够在单元测试中模拟的内容。