在 ASP.NET Core Web-Api 中用 Interlocked.Exchange(ref oldValue, newValue) 替换不可变数据结构是否安全
Is it safe to replace immutable data structure with Interlocked.Exchange(ref oldValue, newValue) in ASP.NET Core Web-Api
我得到一个 api,它是地理坐标请求的终点。这意味着用户可以搜索他们所在地区的特定位置。同时可以添加新的位置。为了使查询尽可能快,我想我会让 R 树不可更改。也就是说,R-Tree 中没有锁,因为多个线程可以同时读取,没有竞争条件。收集更新,如果例如收集了 100 个更新,我想创建一个新的 R-Tree 并替换旧的。现在我的问题是如何做到最好?
我有一个 SearchService,它存储为单音,并有一个 R-Tree 作为私有实例。
在我的Startup.cs
services.AddSingleton<ISearchService, SearchService>();
ISearchService.cs
public interface ISearchService
{
IEnumerable<GeoLocation> Get(RTreeQuery query);
void Update(IEnumerable<GeoLocation> data);
}
SearchService.cs
public class SearchService : ISearchService
{
private RTree rTree;
public IEnumerable<GeoLocation> Get(RTreeQuery query)
{
return rTree.Get(query);
}
public void Update(IEnumerable<GeoLocation> data)
{
var newTree = new RTree(data);
Interlocked.Exchange<RTree>(ref rTree, newTree);
}
}
我的问题是,如果我用 Interlock.Exchange() 交换引用,操作是原子的,不应该有竞争条件。但是,如果线程仍然使用旧实例来处理它们的请求,会发生什么情况。会不会是垃圾收集器在线程仍在访问它时删除了旧实例?毕竟,不再有对旧实例的引用。
我对这个话题比较陌生,所以欢迎任何帮助。感谢您的支持!
读取和写入 references 是 atomic,这意味着不会有对齐问题。但是,它们可能会过时。
CLI 规范第 12.6.6 节
Unless explicit layout control (see Partition II (Controlling Instance
Layout)) is used to alter the default behavior, data elements no
larger than the natural word size (the size of a native int) shall be
properly aligned. Object references shall be treated as though they
are stored in the native word size.
关于 GC,您的树在 运行 Get
时不会被垃圾回收。
所以总而言之,就参考原子性而言,你的方法是线程安全的,你也可以使用Update
方法并安全地覆盖reference,不需要Interlocked.Exchange
。您当前的实施可能发生的最糟糕的情况是您只是得到一棵您提到的陈旧树不是问题。
我得到一个 api,它是地理坐标请求的终点。这意味着用户可以搜索他们所在地区的特定位置。同时可以添加新的位置。为了使查询尽可能快,我想我会让 R 树不可更改。也就是说,R-Tree 中没有锁,因为多个线程可以同时读取,没有竞争条件。收集更新,如果例如收集了 100 个更新,我想创建一个新的 R-Tree 并替换旧的。现在我的问题是如何做到最好?
我有一个 SearchService,它存储为单音,并有一个 R-Tree 作为私有实例。
在我的Startup.cs
services.AddSingleton<ISearchService, SearchService>();
ISearchService.cs
public interface ISearchService
{
IEnumerable<GeoLocation> Get(RTreeQuery query);
void Update(IEnumerable<GeoLocation> data);
}
SearchService.cs
public class SearchService : ISearchService
{
private RTree rTree;
public IEnumerable<GeoLocation> Get(RTreeQuery query)
{
return rTree.Get(query);
}
public void Update(IEnumerable<GeoLocation> data)
{
var newTree = new RTree(data);
Interlocked.Exchange<RTree>(ref rTree, newTree);
}
}
我的问题是,如果我用 Interlock.Exchange() 交换引用,操作是原子的,不应该有竞争条件。但是,如果线程仍然使用旧实例来处理它们的请求,会发生什么情况。会不会是垃圾收集器在线程仍在访问它时删除了旧实例?毕竟,不再有对旧实例的引用。
我对这个话题比较陌生,所以欢迎任何帮助。感谢您的支持!
读取和写入 references 是 atomic,这意味着不会有对齐问题。但是,它们可能会过时。
CLI 规范第 12.6.6 节
Unless explicit layout control (see Partition II (Controlling Instance Layout)) is used to alter the default behavior, data elements no larger than the natural word size (the size of a native int) shall be properly aligned. Object references shall be treated as though they are stored in the native word size.
关于 GC,您的树在 运行 Get
时不会被垃圾回收。
所以总而言之,就参考原子性而言,你的方法是线程安全的,你也可以使用Update
方法并安全地覆盖reference,不需要Interlocked.Exchange
。您当前的实施可能发生的最糟糕的情况是您只是得到一棵您提到的陈旧树不是问题。