如何设置Unity使得类可以异步初始化而不会阻塞其他模块的负载(仅阻止明确需要异步类型实例的其他类型)?我正在考虑的类是参考数据缓存,它从数据库中获取常用数据的快照,我需要在让任何其他模块访问它之前完成预先缓存(如果请求在我的类中被阻止我将快速占用主线程并阻止所有其他模块初始化)。这变得更加重要,因为我有多个这样的参考数据类
举个例子,假设我有一个这样的课程:
public class ProductCache{
public ProductCache(){}
public Initialize(){
// a very slow DB call to fetch frequently used products
Thread.Sleep(30*1000);
}
public Product FindProduct(string productDescription){
/* check cache, if not there try the db */
}
}
如果我从构造函数中调用Initialize,我将阻止调用它的线程(来自Unity)30秒,从而阻止我并行创建其他(类似)类。如果我只是将任务放在线程池上Unity最终会到达需要我的产品缓存的另一个类正在执行其初始化代码的点,然后它访问尚未完全初始化的数据结构(在这种情况下,它将导致在缓存未命中和调用db来获取特定产品,并且在30秒内可能会有许多此类请求)
感谢 奥斯卡
答案 0 :(得分:1)
您需要列出正在运行的任务,并行执行它们,并使用Task.WaitAll()等待它们完成后再继续。
在.Net 4中,这应该可行,并且错误处理变得容易:
public void InitializeAll()
{
List<Task> initTasks = new List<Task>();
ProductCache productCache = new ProductCache();
SomeOtherCache someOtherCache = new SomeOtherCache();
initTasks.Add(Task.Factory.StartNew(() => productCache.Initialize()));
initTasks.Add(Task.Factory.StartNew(() => someOtherCache.Initialize()));
try
{
Task.WaitAll(initTasks.ToArray());
}
catch (AggregateException ex)
{
Console.WriteLine("Oh dear!");
}
}
在老式.Net中,试试这个。我假设你正在为每个可初始化的对象使用一个接口,我遗漏了错误处理:
public void InitializeAll(IEnumerable<IInitializable> initializeUs)
{
List<WaitHandle> handles = new List<WaitHandle>();
foreach(IInitializable init in initializeUs)
{
// Make a copy of the reference in the local scope
IInitializable temp = init;
ManualResetEvent done = new ManualResetEvent(false);
handles.Add(done);
ThreadPool.QueueUserWorkItem(delegate
{
try
{
temp.Initialize();
}
finally
{
done.Set();
}
});
}
// Wait for all the handles to be set
WaitHandle.WaitAll(handles.ToArray());
}