代码之家  ›  专栏  ›  技术社区  ›  julian bechtold

复制结构会导致结构c为空#

  •  0
  • julian bechtold  · 技术社区  · 2 年前

    问题

    我在多线程环境中有一种奇怪的行为:结构中的值在运行时是空的,但在中断模式下包含一些内容。

    给定以下函数:

    public static double Convert_CurrencyValue(SlimOrderbook orderBook,
        double amountToConvert, bool backward = false)
    {
        OrderBookPrice price;
        double result;
        if (!backward)
        {
            price = orderBook.Bids[0];
            result = amountToConvert * price.Price;
        }
        else
        {
            price = orderBook.Asks[0];
            result = amountToConvert / price.Price;
        }
        if (double.IsInfinity(result) || double.IsNaN(result))
        {
            { /* break marker here "/ }
        }
        return result;
    }
    

    出于某种原因,有时(并不总是)结果会是无穷大的。
    我添加了if语句和一个break标记,看看到底发生了什么。
    在该问题的情况下, OrderbookPrice price 等同于以下内容:

    double Price: 0;
    double ImpliedProfit: 0;
    double Volume: 0;
    

    同时当在中断标记中时, SlimOrderbook orderBook.Asks[0] 等同于以下内容:

    double Price: 42.5232;
    double ImpliedProfit: -0.01;
    double Volume: 0.43;
    

    这是我的调试视图的屏幕截图: Screenshot

    基本功能:

    主要涉及的两个数据结构是 class Orderbook struct SlimOrderbook

    SlimOrderbook:

    public struct SlimOrderbook
    {
        public SlimOrderbook(OrderBookPrice[] asks, double spot, OrderBookPrice[] bids)
        {
            Asks = asks;
            SpotPrice = spot;
            Bids = bids;
        }
        public OrderBookPrice[] Asks { get; private set; }
        public double SpotPrice { get; private set; }
        public OrderBookPrice[] Bids { get; private set; }
    }
    public struct OrderBookPrice
    {
        public double Price;
        public double Volume;
        public double ImpliedProfit;
    }
    

    SlimOrderbook正在从中生成 OrderBook 作为一次性工作副本,可在本地使用:

    public SlimOrderbook GetOrderBook(Currency baseCurrency, Currency quoteCurrency)
    {
        if (baseCurrency.Equals(CurrencyPair.BaseCurrency) && quoteCurrency.Equals(CurrencyPair.QuoteCurrency))
        {
            return new SlimOrderbook(asks: (OrderBookPrice[])Asks.Clone(), spot: SpotPrice, bids: (OrderBookPrice[])Bids.Clone());
        }
        else if (baseCurrency.Equals(CurrencyPair.QuoteCurrency) && quoteCurrency.Equals(CurrencyPair.BaseCurrency))
        {
            return new SlimOrderbook(asks: (OrderBookPrice[])InvertedAsks.Clone(), spot: InvertedSpotPrice, bids: (OrderBookPrice[])InvertedBids.Clone());
        }
        else
        {
            throw new ArgumentException($"BaseCurrency {baseCurrency} or QuoteCurrency{quoteCurrency} does not match Orderbook currencies!");
        }
    }
    

    尝试的修复:

    • 我变了 result = amountToConvert / price.Price; result = amountToConvert / orderBook.Asks[0].Price; 没有成功。

    • 我变了 GetOrderBook() 以便在结构中存储数组副本而不是引用。

    0 回复  |  直到 2 年前
        1
  •  0
  •   julian bechtold    2 年前

    代码存在两个问题:

    1. 正如Charlieface在他的第一条评论中提到的那样, array 是引用类型,而不是值类型。这导致中的更新 Orderbook 反映在 SlimOrderbook

    2. Slimorderbook的作用是为线程本地处理提供订单簿的快照/副本。结构中的引用类型仍然是引用类型,不会复制为值类型。

    事实证明, InvertedAsks 以非原子方式从另一个线程更新。 (OrderBookPrice[])InvertedAsks.Clone() 因此复制了当前正在更新的订单簿。

    可以通过首先创建新的 OrderBookPrice[] ,更新它,然后替换中的引用 OrderBook :

    OrderBookPrice[] newInvertedBids = new OrderBookPrice[Bids.Length];
    for (int i = 0;i < Bids.Length;i++)
    {
        newInvertedBids[(Bids.Length-1)- i].Price = 1/Bids[i].Price;
        newInvertedBids[(Bids.Length-1)- i].Volume = Bids[i].Volume;
    }
    InvertedAsks = newInvertedBids;