C#到Java延迟敏感类的转换,在我的情况下,TreeMap会取代SortedList吗
本文关键字:情况下 我的 TreeMap SortedList 取代 转换 延迟 Java | 更新日期: 2023-09-27 18:26:44
我在Java中复制一个C#类。(我是Java新手。)
我的类需要跟踪与doubles相关联的int值。然后,每当一个值越过doubles的下方或上方时,它需要创建一个Alerter(int)。
Alerter.LatencySensiveAction(),需要立即调用,它是对延迟敏感且时间关键的代码。DoubleMap类的目的是尽可能快地调用LatencySensiveAction()。
DoubleMap.OnData()是该类的延迟敏感方法(如下)。
树映射有意义吗?我在C#中使用SortedList。我正在寻找一个关联集合,它以排序的顺序存储键/值对,并具有快速遍历功能。
我被告知这个Java代码
for (Map.Entry<Double,Alerter> entry : mAscend.entrySet() )
效率不高,因为它创建了一个新对象。我应该用什么代替?
因此,基本上,我想问的是,使用什么集合可以将double与int关联起来,并按排序顺序存储,以及按顺序遍历集合的最快方法是什么。
我相信我的C#代码(下面)能完成这项工作,需要帮助将其转换为Java。如果你认为我的C#代码也可以改进。。请告诉我。。ty。
Java代码:
public class DoubleMap {
TreeMap<Double,Alerter> mAscend, mDecend, mHoldAscend, mHoldDecend;
public DoubleMap()
{
mAscend = new TreeMap<Double, Alerter>();
mDecend = new TreeMap<Double, Alerter>(new ReverseComparator());
}
public void Add(boolean rAscend, double value, int size)
{
TreeMap<Double,TradeOrder> list = rAscend ? mAscend : mDecend;
Alerter to = list.get(value);
if ( to != null )
{
Alerter.size += size;
}
else
{
to = new Alerter (size);
list.put(value, to);
}
}
public void Remove(boolean rAscend, double value, int size)
{
TreeMap<Double,TradeOrder> list = rAscend ? mAscend : mDecend;
Alerter to = list.get(value);
if ( to != null )
{
long nsize = to.size - size;
if ( nsize <= 0 )
list.remove(value);
else
to.size = nsize;
}
}
public void Ondata(double rValue)
{
for (Map.Entry<Double,Alerter> entry : mAscend.entrySet() )
{
if ( entry.getKey() > rValue )
break;
entry.getValue().LatencySensitiveAction();
if ( mHoldAscend == null )
mHoldAscend = new TreeMap<Double,Alerter>(mHoldAscend);
mAscend.remove(entry.getKey());
}
for (Map.Entry<Double,TradeOrder> entry : mDecend.entrySet() )
{
if ( entry.getKey() < rValue )
break;
entry.getValue().LatencySensitiveAction();
if ( mHoldDecend == null )
mHoldDecend = new TreeMap<Double,TradeOrder>(mHoldDecend);
mHoldDecend.remove(entry.getKey());
}
if ( mHoldAscend != null )
{
mAscend = mHoldAscend;
mHoldAscend = null;
}
if ( mHoldDecend != null )
{
mDecend = mHoldDecend;
mHoldDecend = null;
}
}
}
C#代码:
public class DoubleMap
{
private SortedList<double, Alerter> mAscend, mDecend, mHoldAscend, mHoldDecend;
public DoubleMap()
{
mAscend = new SortedList<double, Alerter>();
mDecend = new SortedList<double, Alerter>(new DescendingComparer<double>());
}
public void Add(bool rAscend, double rValue, long rSize)
{
var list = rAscend ? mAscend : mDecend;
Alerter to;
if (list.TryGetValue(rValue, out to))
{
to.Size += rSize;
}
else
{
to = new Alerter(rSize);
list.Add(rValue, to);
}
}
public void Remove(bool rAscend, double rValue, long rSize)
{
var list = rAscend ? mAscend : mDecend;
Alerter to;
if (list.TryGetValue(rValue, out to))
{
long nqty = to.Size - rSize;
if (nqty <= 0)
{
list.Remove(rValue);
}
else
to.Size = nqty;
}
}
public void OnData(double rValue)
{
foreach (var pair in mAscend)
{
if (pair.Key > rValue)
break;
pair.Value.LatencySensitiveAction();
if (mHoldAscend == null)
mHoldAscend = new SortedList<double, Alerter>(mAscend);
mHoldAscend.Remove(pair.Key);
}
foreach (var pair in mDecend)
{
if (pair.Key < rValue)
break;
pair.Value.LatencySensitiveAction();
if (mHoldDecend == null)
mHoldDecend = new SortedList<double, Alerter>(mDecend, new DescendingComparer<double>());
mHoldDecend.Remove(pair.Key);
}
if (mHoldAscend != null)
{
mAscend = mHoldAscend;
mHoldAscend = null;
}
if (mHoldDecend != null)
{
mDecend = mHoldDecend;
mHoldDecend = null;
}
}
}
class DescendingComparer<T> : IComparer<T> where T : IComparable<T>
{
public int Compare(T x, T y)
{
return y.CompareTo(x);
}
}
如果延迟对您来说非常重要,我建议实现一个自定义类来处理您的订单簿(这是一个订单簿,对吧?:-))
我建议如下:
- 一个表示价格的doubles数组(请注意,为什么要使用doubles?这不应该是BigDecimal或不动点整数以避免浮点不准确吗?)
- 订单大小的对应长数组
- 相应的警报器阵列
- 根据价格对所有阵列进行排序
- 然后,您可以直接在价格数组上使用二进制搜索来查找任何给定范围内的价格
这种方法将为您提供非常低的延迟。
不利的一面是添加/删除订单是O(n)。但它是一个只有三个arraycopy
的廉价O(n),除非你的订单量很大,否则开销会很低,你不会注意到。
您可能还对Javolution感兴趣,它包含一组非常低延迟的Java库,我认为其中一些库是专门为交易应用程序设计的。
如果您只进行遍历,为什么要使用映射?不能在小于O(n)的时间内执行遍历。
我建议您制作一个对象来封装订单,并查看您的集合的PriorityQueue。
如果你需要进行范围搜索,你也可以查看TreeSet(如果你的值是唯一的)或TreeMap。(但请注意,您必须以某种方式进行迭代,才能从这些类中获得排序输出。)
编辑
你确定你的评审员的意思是for (Map.Entry<Double,Alerter> entry : mAscend.entrySet())
效率低下,而不是for循环中的代码吗?每次匹配一对时,都要执行新的集合创建(这本身不是一项廉价的工作,在时间敏感的代码中当然也不是一件好事)。您在C#代码中也在做同样的事情。
试试这个:
Code Deleted; See history
编辑2
我意识到您的实现实际上比必要的慢得多,因为它只依赖于TreeMap来进行排序和查找。这里有一个更快的实现:
public class DoubleMap {
HashMap<Double, Alerter> mAscend, mDescend;
PriorityQueue<Double> pricesAscending, pricesDescending;
public DoubleMap()
{
pricesAscending = new PriorityQueue<Double>(100);
pricesDescending = new PriorityQueue<Double>(100, new ReverseComparator());
}
public void Add(boolean rAscend, double value, int size)
{
Map<Double, Alerter> map = rAscend ? mAscend : mDescend;
Alerter to = map.get(value);
if ( to != null )
{
Alerter.size += size;
}
else
{
to = new Alerter (size);
map.put(value, to);
pricesAscending.offer(value);
pricesDescending.offer(value);
}
}
public void Remove(boolean rAscend, double value, int size)
{
Map<Double, Alerter> map = rAscend ? mAscend : mDecend;
Alerter to = map.get(value);
if ( to != null )
{
long nsize = to.size - size;
if ( nsize <= 0 )
map.remove(value);
pricesAscending.remove(value);
pricesDescending.remove(value);
else
to.size = nsize;
}
}
public void Ondata(double rValue)
{
while (pricesAscending.peek() < rValue) {
mAscend.getValue(pricesAscending.peek()).LatencySensitiveAction();
mAscend.remove(pricesAscending.poll());
}
while (pricesDescending.peek() > rValue) {
mDescend.getValue(pricesDescending.peek()).LatencySensitiveAction();
mDescend.remove(pricesDescending.poll());
}
}
}
差异:HashMap具有恒定时间的get()
和remove()
操作,其中TreeMap对于这些操作具有O(log(n))
性能。
PriorityQueue具有恒定时间peek()
和poll()
性能。
在现代操作系统上处理"低延迟"应用程序时,需要记住的一件事是它是先发制人的。它不是一个实时操作系统,因此任何线程都可以在任何时候挂起,并且不能保证响应时间。如果您试图实现诚实的低延迟/一致延迟,那么至少您需要在任务调度程序中将应用程序推送到实时状态。虽然这不是真正的实时,但它将帮助您的线程获得更多的处理器时间。还要考虑GC可以停止线程进行清理。
如果你真的对实现最低的延迟感兴趣,或者至少有一个更有保证的延迟,那么我至少会切换到C++或C。至少这样你就可以控制你的内存分配,不必担心GC会在你下面导致意外的延迟。