use*_*375 5 c# multithreading dependency-injection autofac
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在标记为#1的示例中,我正在解析IWork并执行一些操作。对于单线程环境,我了解DI中的情况,如何使用DI,lifetimescope以及如何解决依赖关系。
但是我很难理解多线程环境中的DI。我尝试证明样本2,样本3中存在的一些问题。在这些示例中,我将需要解决LifetimeScope中的依赖关系,该依赖关系将为ColabManualWork中的每个线程创建。当然,我不想在Autofac的任何类上进行引用以防止耦合。
我什至创建了一个简单的工厂,该工厂适合于从当前工厂中创建嵌套的LifetimeScope:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是我不太喜欢这种解决方案。有三个大问题-1)所有逻辑都必须在lambda函数(或等效方法)中;2)如果将来再次处置父范围,Autoflac可以重新实现处置子范围的功能(此功能已经使用了几个月);3)如示例3所示,我可以在启动ColabManualWork中的任何功能之前就处置父级LifetimeScope,因此我的工厂将使用已经处置的LifetimeScope。
有人可以帮助我如何有效地解决工作线程中的问题吗?我读了一些与SimpleInjector有关的东西,它在多线程应用程序中使用依赖注入进行工作,但是我没有完全理解它,而且它与Autofac不相关。在该文章中写的是 在多线程应用程序中,每个线程应该获得自己的对象图。这意味着您通常应该在线程执行开始时调用一次container.GetInstance()以获得用于处理该线程的根对象
如何在不与Autofac耦合以及与线程相关的lifescope耦合的情况下解决工作线程中的依赖关系?
要为每个线程提供自己的生命周期范围,您只需将您的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);
}
}
Run Code Online (Sandbox Code Playgroud)
您的担忧 1) 可以通过使用不同的抽象来解决。例如,您可以将其添加到IsolatedLifetimeScopeFactory
public Autofac.Features.OwnedInstances.Owned<TA> Create()
{
return _scope.Resolve<Autofac.Features.OwnedInstances.Owned<TA>>();
}
Run Code Online (Sandbox Code Playgroud)
如果你真的愿意的话,你可以隐藏Owned在抽象背后,尽管我会说这太过分了。
| 归档时间: |
|
| 查看次数: |
3474 次 |
| 最近记录: |