Note that there are some explanatory texts on larger screens.

plurals
  1. POVectorizing operations in a contained class without breaking class structure
    primarykey
    data
    text
    <p>My current project is split into multiple classes that correctly represent the way we think of the entities in the system. However, this is taking a performance price, so I'm trying to come up with a way of improving performance while maintaining the current class structure we have.</p> <p>I think an example will best illustrate the problem: Let's say I have an <code>Order</code> class that contains multiple <code>Item</code>s. A naive implementation for shipping an <code>Order</code> is shipping all of its <code>Item</code>s:</p> <pre><code>class Order { private List&lt;Item&gt; m_items; public void Ship() { foreach (Item item in m_items) { item.Ship(); } } } </code></pre> <p>Shipping an <code>Item</code> is a multi-stage process:</p> <pre><code>class Item { public void Ship() { var receipt = m_boat.ShipToDestination(this); ProcessReceipt(receipt); } } </code></pre> <p>As it turns out, shipping the <code>Item</code> on a <code>Boat</code> takes a long time. Luckily, the <code>Boat</code> can ship multiple <code>Item</code>s concurrently (<code>List&lt;Receipt&gt; Boat.ShipToDestination(List&lt;Item&gt; items)</code>). However, to use this method I will have to rewrite <code>Order.Ship()</code> as follows:</p> <pre><code>class Order { public void Ship() { var receipts = m_boat.ShipToDestination(m_items); foreach (Receipt receipt in receipts) { ProcessReceipt(receipt); } } } </code></pre> <p>This means that <code>ProcessReceipt</code> is now part of <code>Order</code> (rather than <code>Item</code>), and also that an <code>Item</code> no longer takes care of all of its shipping logistics.</p> <p>In my real code there are many methods with this problem, so using this solution effectively means that most of the <code>Item</code> logic will move into the <code>Order</code> class. However, this seems like the wrong place to have this logic - it really should be in <code>Item</code>.</p> <p>I considered using multiple threads (e.g. using a <code>Task</code> per <code>Item</code>) but this seems too wasteful, especially since an <code>Order</code> can have dozens of <code>Items</code>.</p> <p>Another approach I considered is creating a <code>QueuedBoat</code> with a <code>QueueForShipping(Item item)</code> method and a <code>ShipQueuedItems()</code> method. Now <code>Order</code> can call <code>ShipQueuedItems</code> while <code>Item</code> can call <code>QueueForShipping</code>. The problem with this approach is that in my real code, the <code>Receipt</code> is returned only after the <code>Item</code> was shipped, so the code would have to look like this:</p> <pre><code>class Order { private List&lt;Item&gt; m_items; public void Ship() { foreach (Item item in m_items) { item.Ship(); } m_queuedBoat.ShipQueuedItems(); foreach (Item item in m_items) { item.FinalizeShipping(); } } } class Item { public void Ship() { m_queuedBoat.QueueForShipping(this); } public void FinalizeShipping() { ProcessReceipt(m_queuedBoat.GetReceiptForItem(this)); } } </code></pre> <p>This feels like it's in the right direction (since <code>Order</code> knows how many <code>Item</code>s it has, it must be the component that knows when everything is on the <code>Boat</code>), but it broke <code>Ship</code> into two stages. In my real code I have multiple stages (each can be vectorized separately), so the method would be broken into 3-4 pieces, which is not a pretty sight.</p> <p>Can someone suggest a way of vectorizing <code>Item.Ship()</code> while keeping the business logic inside the <code>Item</code> class, or will I have to give up on the Order/Item separation in order to take advantage of vectorization?</p> <p><strong>Edit:</strong></p> <p>Another approach could be this:</p> <pre><code>class Order { private List&lt;Item&gt; m_items; public void Ship() { for (int i = 0; i &lt; m_items.Count; ++i) { bool isLast = (i == (m_items.Count - 1)); item.Ship(isLast); } } } class Item { public void Ship(bool isLast) { m_queuedBoat.QueueForShipping(this, FinalizeShipping); if (isLast) m_queuedBoat.ShipQueuedItems(); } private void FinalizeShipping(Receipt receipt) { ProcessReceipt(receipt); } } </code></pre> <p>Where the <code>QueuedBoat</code> class invokes a callback for each item with its <code>Receipt</code>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload