﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2021 (c) 2026</copyright><ttl>60</ttl><item><title>James Newton-King commented on Caching, the funny way</title><description>There isn't just the cost of lock before adding, you also have to safe guard that a dictionary doesn't change while you're getting a value from it.

But no I've never done any performance tests around it.</description><link>http://ayende.com/17409/caching-the-funny-way#comment22</link><guid>http://ayende.com/17409/caching-the-funny-way#comment22</guid><pubDate>Wed, 22 Jun 2011 11:27:37 GMT</pubDate></item><item><title>James Newton-King commented on Caching, the funny way</title><description>There isn't just the cost of lock before adding, you also have to safe guard that a dictionary doesn't change while you're getting a value from it.

But no I've never done any performance tests around it.</description><link>http://ayende.com/17409/caching-the-funny-way#comment21</link><guid>http://ayende.com/17409/caching-the-funny-way#comment21</guid><pubDate>Wed, 22 Jun 2011 11:27:31 GMT</pubDate></item><item><title>Luke commented on Caching, the funny way</title><description>Have you done any empirical tests showing that recreating the dictionary is actually faster than the straightforward lock-before-adding approach?</description><link>http://ayende.com/17409/caching-the-funny-way#comment20</link><guid>http://ayende.com/17409/caching-the-funny-way#comment20</guid><pubDate>Tue, 21 Jun 2011 13:50:57 GMT</pubDate></item><item><title>James Newton-King commented on Caching, the funny way</title><description>I use the same approach in Json.NET for caching reflection data. It has been in the wild for years and I've yet to have any problems with it.</description><link>http://ayende.com/17409/caching-the-funny-way#comment18</link><guid>http://ayende.com/17409/caching-the-funny-way#comment18</guid><pubDate>Sun, 19 Jun 2011 20:38:24 GMT</pubDate></item><item><title>Mike commented on Caching, the funny way</title><description>Earlier version of Rx for .net 3.5 contained backported System.Threading assembly.
Last place I see them is here: http://code.google.com/p/rx-samples/source/browse/trunk/lib/Net35/?r=10

Also there are many nice LINQ in System.Interactive (also from .net 4)</description><link>http://ayende.com/17409/caching-the-funny-way#comment17</link><guid>http://ayende.com/17409/caching-the-funny-way#comment17</guid><pubDate>Fri, 17 Jun 2011 10:31:59 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Daniel,
Very good point, yes. I haven't considered that, memory models usually make my head hurt.</description><link>http://ayende.com/17409/caching-the-funny-way#comment16</link><guid>http://ayende.com/17409/caching-the-funny-way#comment16</guid><pubDate>Fri, 17 Jun 2011 08:31:10 GMT</pubDate></item><item><title>Daniel Grunwald commented on Caching, the funny way</title><description>You are also making the assumption that the new dictionary will be initialized and in a valid state before it is published and visible to other threads.

This is not guaranteed for non-volatile fields. The optimizer (or the CPU cache) might re-order the statements and assign the new dictionary to idPropertyChange before the Add() method is called, or even before the constructor has finished running! You need a volatile write to ensure that the dictionary contents are visible to other processors before the reference to the dictionary becomes visible.
However, this is currently only a theoretical problem - the current .NET implementations implicitly treat all writes as volatile.
But processors other than x86/x64 often have weaker memory models where volatile writes don't come for free, so I wouldn't rely on all future .NET implementations to keep this behavior.</description><link>http://ayende.com/17409/caching-the-funny-way#comment15</link><guid>http://ayende.com/17409/caching-the-funny-way#comment15</guid><pubDate>Thu, 16 Jun 2011 18:32:57 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Patrick,
You are correct, expect that we are usually talking about a N &lt; 20, so even with N^20, the cost is negligible.</description><link>http://ayende.com/17409/caching-the-funny-way#comment14</link><guid>http://ayende.com/17409/caching-the-funny-way#comment14</guid><pubDate>Thu, 16 Jun 2011 15:15:33 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Mike,
That is the exact point of having lost writes. In a cache, this is perfectly fine to do.</description><link>http://ayende.com/17409/caching-the-funny-way#comment13</link><guid>http://ayende.com/17409/caching-the-funny-way#comment13</guid><pubDate>Thu, 16 Jun 2011 15:14:56 GMT</pubDate></item><item><title>Mike commented on Caching, the funny way</title><description>@tobi,
 .
Wouldn't your "copy to local" idea just cause new bugs?
What happens two threads both copy to local variables, then add their respective types then both save.
Only one of the two types would be saved.
 .
This is nice if they both happened to be the same type as you suggest, but not so useful if they are different types.  Still, I suppose it is thread safe though.</description><link>http://ayende.com/17409/caching-the-funny-way#comment12</link><guid>http://ayende.com/17409/caching-the-funny-way#comment12</guid><pubDate>Thu, 16 Jun 2011 15:12:03 GMT</pubDate></item><item><title>Patrick Huizinga commented on Caching, the funny way</title><description>hmm, I guess I need to be more careful with  &amp;lt; and &amp;gt; in messages.

For similar reasons people will become violent when you have:
&lt;pre&gt;string s = "";
for (int i = 0; i &amp;lt; 13000; i++)
{
    s += (char) i;
}
&lt;/pre&gt;

You could argue that every iteration is just an O(N) operation, but that guy with the axe won't. ;-)

btw, the code looked fine in the preview at the bottom, so I hereby file that bug :)</description><link>http://ayende.com/17409/caching-the-funny-way#comment11</link><guid>http://ayende.com/17409/caching-the-funny-way#comment11</guid><pubDate>Thu, 16 Jun 2011 13:12:02 GMT</pubDate></item><item><title>Patrick Huizinga commented on Caching, the funny way</title><description>Ayende,

When you add 1 item you have O(N) where N is the amount of items you already have. However, if you want to add N items it will be an O(N^2) operation.

For similar reasons people will become violent when you have:
&lt;pre&gt;string s = "";
for (int i = 0; i &lt; 13000; i++)
{
    s += (char) i;
}&lt;/pre&gt;

You could argue that every iteration is just an O(N) operation, but that guy with the axe won't. ;-)</description><link>http://ayende.com/17409/caching-the-funny-way#comment10</link><guid>http://ayende.com/17409/caching-the-funny-way#comment10</guid><pubDate>Thu, 16 Jun 2011 12:41:17 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Tobi,
Nice catch, yes, it is there.
</description><link>http://ayende.com/17409/caching-the-funny-way#comment9</link><guid>http://ayende.com/17409/caching-the-funny-way#comment9</guid><pubDate>Thu, 16 Jun 2011 11:40:22 GMT</pubDate></item><item><title>tobi commented on Caching, the funny way</title><description>I believe there is a threading bug. The dictionary initializer will call the add method which throws on duplicate keys. And that can happen because you are repeatedly accessing the field which can change. The type you try to add could have just been added.
Fix: Copy the field to a local first.</description><link>http://ayende.com/17409/caching-the-funny-way#comment8</link><guid>http://ayende.com/17409/caching-the-funny-way#comment8</guid><pubDate>Thu, 16 Jun 2011 11:33:26 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Koen,
Yes, this is an O(N) operation, basically, where N is the number of types.
Then again, when you consider how many types there are, it isn't really meaningful.
There are about 13,000 types in the .NET framework, for example. O(N) of that is meaningless, and it is VERY unlikely that you'll get to that level</description><link>http://ayende.com/17409/caching-the-funny-way#comment7</link><guid>http://ayende.com/17409/caching-the-funny-way#comment7</guid><pubDate>Thu, 16 Jun 2011 09:42:31 GMT</pubDate></item><item><title>Patrick Huizinga commented on Caching, the funny way</title><description>Meh, I guess I need to learn to type faster...</description><link>http://ayende.com/17409/caching-the-funny-way#comment6</link><guid>http://ayende.com/17409/caching-the-funny-way#comment6</guid><pubDate>Thu, 16 Jun 2011 09:41:00 GMT</pubDate></item><item><title>Patrick Huizinga commented on Caching, the funny way</title><description>To expand on what Konstantin said:
You assume it doesn't matter if you lose a write to the cache. You assume it doesn't matter that you might 'generate' the identityProperty for the same type twice *and* not return the same value in those cases. (ConcurrentDictionary doesn't guarantee the generating a value only once, but does guarantee always returning the same value)

Besides that you assume the cache will never grow too large. Because by copying the dictionary every time you generate a value, you have yourself an O(n^2) operation there.</description><link>http://ayende.com/17409/caching-the-funny-way#comment5</link><guid>http://ayende.com/17409/caching-the-funny-way#comment5</guid><pubDate>Thu, 16 Jun 2011 09:38:57 GMT</pubDate></item><item><title>Ayende Rahien commented on Caching, the funny way</title><description>Konstantin,
Bing! Exactly, we might lose cached entries, but we don't care about that, since this is a cache, losing values is all right.</description><link>http://ayende.com/17409/caching-the-funny-way#comment4</link><guid>http://ayende.com/17409/caching-the-funny-way#comment4</guid><pubDate>Thu, 16 Jun 2011 09:37:44 GMT</pubDate></item><item><title>Koen commented on Caching, the funny way</title><description>Couldn't this become a rather heavy operation if you have a great amount of types. Everytime this is called on a new type, the cache "expands" and creating the new dictionary instance takes more "time" I would think...

I also had the same thought as Konstantin, but indeed that's not critical for caching...</description><link>http://ayende.com/17409/caching-the-funny-way#comment3</link><guid>http://ayende.com/17409/caching-the-funny-way#comment3</guid><pubDate>Thu, 16 Jun 2011 09:33:25 GMT</pubDate></item><item><title>Konstantin commented on Caching, the funny way</title><description>This solution is OK for cache, but you could lose some entries, written to the cache, between new Dictionary being published and old dictionary being copied over...</description><link>http://ayende.com/17409/caching-the-funny-way#comment2</link><guid>http://ayende.com/17409/caching-the-funny-way#comment2</guid><pubDate>Thu, 16 Jun 2011 09:22:03 GMT</pubDate></item><item><title>Scooletz commented on Caching, the funny way</title><description>- trying getting value does not change the dictionary state (no dirty writes)
- copying values to the new dict uses iterator (no dirty writes)
- as you mentioned, idPropertyCache is replaced in atomic way (pointer)

Summing up, not changing the read dictionary, replacing the read with a new one. That's the clue.</description><link>http://ayende.com/17409/caching-the-funny-way#comment1</link><guid>http://ayende.com/17409/caching-the-funny-way#comment1</guid><pubDate>Thu, 16 Jun 2011 09:11:23 GMT</pubDate></item></channel></rss>