.NET 4.0的System.Lazy<T>类提供了三种线程安全模式,通过枚举LazyThreadSafetyMode实现,我将其总结如下:
- LazyThreadSafetyMode.None - 非线程安全。
- LazyThreadSafetyMode.ExecutionAndPublication - 只有一个并发线程将尝试创建基础值。在成功创建后,所有等待的线程都将接收相同的值。如果在创建过程中出现未处理的异常,则会重新在每个等待的线程上引发该异常,并在每次尝试访问基础值时缓存和重新引发它。
- LazyThreadSafetyMode.PublicationOnly - 多个并发线程将尝试创建基础值,但首先成功的线程将确定传递给所有线程的值。如果在创建过程中出现未处理的异常,则不会缓存它,并且并发的、随后的尝试访问基础值将重试创建并可能成功。
我想要一个延迟初始化的值,它遵循稍微不同的线程安全规则,即:
只有一个并发线程将尝试创建基础值。在成功创建后,所有等待的线程都将接收相同的值。如果在创建过程中出现未处理的异常,则会在每个等待的线程上重新引发该异常,但不会缓存它,随后的尝试访问基础值将重试创建并可能成功。
因此,与LazyThreadSafetyMode.ExecutionAndPublication的关键区别在于,如果创建的“第一次尝试”失败,可以在以后重新尝试。
现有(.NET 4.0)类是否提供此功能,或者我需要自己实现?如果我需要自己实现,是否有一种聪明的方法在实现中重用现有的Lazy<T>以避免显式锁定/同步?
注:对于用例,请想象“创建”可能是昂贵且容易出错的,例如涉及从远程服务器获取大量数据。我不想尝试同时获取多个数据,因为它们可能全部失败或全部成功。但是,如果它们失败了,我希望能够稍后重试。
LazyWithSprinkles<T>
的任何调用者来管理?这听起来像是一个比您发布的问题稍微大一点的问题,这表明需要一个与Lazy<T>
类似但看起来完全不同的解决方案。 - Joe AmentaLazy<Task<T>>
,在第一次请求时,它会启动一个Task<T>
,该任务会重复发出请求,直到最终成功(或抛出无法恢复的错误);然后调用者可以等待该Task<T>
尽可能长的时间。虽然这不完全符合您要求的内容,但是,如果在类似于Lazy<T>
的想法中抛出异常,则有时会在值准备好之前超时100ms...但这实际上与稍后重试有什么区别呢? - Joe Amenta