[英]Autofac - resolving dependencies in multi thread environment
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以及如何解決依賴關系。
但是我在多線程環境中很難理解DI。 我試圖證明我的一些問題是樣品#2,#3。 在這些示例中,我會以某種方式解決LifetimeScope中的依賴關系,這些依賴關系將在ColabManualWork中為每個線程創建。 當然我不希望從Autofac的任何類引用來防止耦合。
我甚至創建了一個簡單的工廠,適合從當前的一個創建嵌套的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。
有人可以幫我解決如何有效解決工作線程中的解決問題嗎? 我在多線程應用程序中閱讀了與SimpleInjector相關的一些名為Work with dependency injection的內容,但我並沒有完全理解它,而且與Autofac不相關。 在那篇文章中編寫了一個多線程應用程序,每個線程都應該得到自己的對象圖。 這意味着您通常應該在線程執行開始時調用container.GetInstance()一次以獲取用於處理該線程的根對象
如何解決工作線程中的依賴關系而不與Autofac和線程相關的lifetimescope耦合?
要為每個線程提供自己的生命周期范圍,只需將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
,雖然我會說這太過分了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.