gpt4 book ai didi

c# - Autofac - 解决多线程环境中的依赖关系

转载 作者:太空狗 更新时间:2023-10-29 23:30:19 24 4
gpt4 key购买 nike

public class MultithreadTester
{

public void Run()
{
var builder = new ContainerBuilder();
builder.RegisterType<ManualWork>().As<IWork>();
builder.RegisterType<ColabManualWork>().As<IColabWork>();
builder.RegisterType<RelaxAfterManualWork>().As<IRelax>();

var container = builder.Build();

//#1 - Simple single thread
using (var scope = container.BeginLifetimeScope())
{
var work = scope.Resolve<IWork>();
work.DoWork();
}

//#2 - Resolving dependecies in worker threads in scopes of these threads without passing lifetime scopes are container into implementation
using (var scope = container.BeginLifetimeScope())
{
var work = scope.Resolve<IColabWork>();
work.DoWork();
}

//#3 - Resolving dependecies in worker threads when original scope is already gone (simulates fast request on same service which spawns threads for request processing)
IColabWork workForSample3;
using (var scope = container.BeginLifetimeScope())
{
workForSample3 = scope.Resolve<IColabWork>();
}
workForSample3.DoWork();

Console.ReadKey();

}

public interface IRelax
{
void DoRelax();
}

public class RelaxAfterManualWork : IRelax
{
public void DoRelax()
{
Console.WriteLine("Relaxing after hard work...");
Thread.Sleep(1000);
Console.WriteLine("Relax is done...");
}
}


public interface IWork
{
void DoWork();
}

public class ManualWork : IWork
{
private readonly IRelax _relaxActivity;

public ManualWork(IRelax relaxActivity)
{
_relaxActivity = relaxActivity;
}

public void DoWork()
{
Console.WriteLine("Ufff, this is so hard...");
Thread.Sleep(5000);
Console.WriteLine("Work is done...");
_relaxActivity.DoRelax();
}
}

public interface IColabWork
{
void DoWork();
}

public class ColabManualWork : IColabWork
{
public void DoWork()
{
Console.WriteLine("We must discuss how to share the workload...");
Thread.Sleep(1500);

Action action = () =>
{
//IT WOULD BE FINE TO HAVE RESOLVED DEPENDENCIES PER THREAD AND IN THREAD OWN LIFETIMESCOPE

Console.WriteLine("Ufff, this is so hard but working with my buddies helps...");
Thread.Sleep(2500);
Console.WriteLine("Work is done...");
var relaxActivity = new RelaxAfterManualWork();
relaxActivity.DoRelax();
};

var thread1 = new Thread(() => { action(); });
var thread2 = new Thread(() => { action(); });
thread1.Start();
thread2.Start();

thread1.Join();
thread2.Join();
}
}


}

在标记为 #1 的示例中,我正在解析 IWork 并运行一些操作。对于单线程环境,我了解 DI 中发生的事情、我应该如何使用 DI、lifetimescope 以及如何解决依赖关系。

但是我很难理解多线程环境下的依赖注入(inject)。我试图证明我遇到的一些问题是示例 #2、#3。在这些示例中,我会以某种方式需要解决 LifetimeScope 中的依赖关系,这些依赖关系将为 ColabManualWork 中的每个线程创建。当然,我不希望引用 Autofac 中的任何类以防止耦合。

我什至创建了一个简单的工厂,它适合从当前的 LifetimeScopes 创建嵌套的 LifetimeScopes:

public interface IIsolatedLifetimeScopeFactory<TA>
{
void Create(Action<TA> action);
}

public class IsolatedLifetimeScopeFactory<TA> : IIsolatedLifetimeScopeFactory<TA>
{
private readonly ILifetimeScope _scope;

public IsolatedLifetimeScopeFactory(ILifetimeScope scope)
{
_scope = scope;
}

public void Create(Action<TA> action)
{
using (var subScope = _scope.BeginLifetimeScope())
{
var a = subScope.Resolve<TA>();
action(a);
}
}
}

但我不太喜欢这个解决方案。存在三个大问题 - 1)所有逻辑必须在 lambda 函数(或等效方法)中; 2)如果父作用域再次被处置,Autoflac 将来可以重新实现处置子作用域的功能(这个功能已经存在几个月了); 3) 如示例 #3 中所示,我可以在 ColabManualWork 中的任何功能启动之前处置父 LifetimeScope,因此我的工厂将使用已经处置的 LifetimeScope。

有人可以帮助我如何有效地解决工作线程中的问题吗?我读了一些与名为 Work with dependency injection in multi-threaded applications 的 SimpleInjector 相关的内容但我没有完全理解它,而且它与 Autofac 无关。在那篇文章里写着在多线程应用程序中,每个线程都应该有自己的对象图。这意味着您通常应该在线程开始执行时调用一次 container.GetInstance() 以获取用于处理该线程的根对象

如何在不与 Autofac 耦合的情况下解决工作线程中的依赖关系以及线程相关的生命周期?

最佳答案

要为每个线程提供自己的生命周期范围,您只需将 IsolatedLifetimeScopeFactory 注册为 SingleInstance。这将解决您的问题 2) 和 3)

[TestMethod]
public void MyTestMethod()
{
var cb = new ContainerBuilder();
cb.RegisterGeneric(typeof(IsolatedLifetimeScopeFactory<>))
.SingleInstance();
var container = cb.Build();

using (var scope1 = container.BeginLifetimeScope("scope1"))
using (var scope2 = scope1.BeginLifetimeScope("scope2"))
{
var factory = scope2.Resolve<IsolatedLifetimeScopeFactory<object>>();
var tag = factory._scope.Tag; // made _scope public for testing purposes
Assert.AreNotEqual("scope1", tag);
Assert.AreNotEqual("scope2", tag);

// This particular string "root" is probably not guaranteed behavior, but
// being in the root scope is guaranteed for SingleInstance registrations.
Assert.AreEqual("root", tag);
}
}

您关注的问题 1) 可以通过使用不同的抽象来解决。例如,您可以将其添加到 IsolatedLifetimeScopeFactory

public Autofac.Features.OwnedInstances.Owned<TA> Create()
{
return _scope.Resolve<Autofac.Features.OwnedInstances.Owned<TA>>();
}

如果您真的愿意,您可以将 Owned 隐藏在抽象之后,尽管我认为这有点矫枉过正。

关于c# - Autofac - 解决多线程环境中的依赖关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31705624/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com