﻿<?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>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter, 
  
I'll put up a post that shows what is actually going on in more details, that would explain that.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment38</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment38</guid><pubDate>Sun, 31 Oct 2010 12:24:43 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>You already have locking, you'll just be moving it elsewhere.
  
  
If the calling code only handles one document at a time then there is somewhere where it is added to a list of documents otherwise your own code would only be dealing with one document at a time too.
  
  
"Reducing the number of UI calls far outstrips any thread scheduling concerns that I can have"
  
  
It's a false dichotomy, it is possible to write code which both schedules threads properly and has the same number of IO calls; you don't have to choose between the two.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment37</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment37</guid><pubDate>Sun, 31 Oct 2010 12:23:34 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
Making the class thread safe would means that I have locking, which I want to avoid.
  
And the calling code doesn't handle a list of documents, it handle only one doc at a time.
  
  
And yes, I'll wake up a lot of threads, but that is cheap to do, since they will wake up, do some minute amount of work, then block on IO, anyway.
  
Reducing the number of IO calls far outstrips any thread scheduling concerns that I can have.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment36</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment36</guid><pubDate>Sun, 31 Oct 2010 12:15:08 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>You'd only need to make the target class thread safe (the class which holds the index information, if that is what we are talking about?)
  
  
If your calling code is aware of all of the documents which need updating then you can pass them to the thread pool as a batch of jobs.
  
  
pseudo code...
  
  
foreach(Index in indexes)
  
{
  
  post a job to the thread pool for (index, listOfDocuments)
  
}
  
  
If you have 32 jobs to do per document and you only have 4 CPU cores you are going to wake up lots of threads which cannot all execute concurrently and that will slow down your performance.
  
  
It's just that it looks like a rethink of how you call this routine could not only make it more simple to develop (and understand) the code but improve the performance too.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment35</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment35</guid><pubDate>Sun, 31 Oct 2010 12:09:34 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
That would require me to handle multiple levels of locking (one for each thread), would force me to remember all the pending state, etc.
  
In this fashion, the only thing I need to remember is the last handled item.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment34</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment34</guid><pubDate>Sun, 31 Oct 2010 12:00:42 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>That's sounds like an implementation issue not a threading one.
  
  
You wouldn't start a thread from the pool for every document in a batch, you'd queue one job with the batch of documents as the data packet it needs to work on.
  
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment33</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment33</guid><pubDate>Sun, 31 Oct 2010 11:57:12 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
Assume the following:
  
  
Doc A is written
  
Doc B is written
  
  
Each is an independent operation.
  
  
We have two separate indexes.
  
  
Using your approach, we will have 4 separate writes.
  
Using mine, we will have 2.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment32</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment32</guid><pubDate>Sun, 31 Oct 2010 11:52:17 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>I think this takes us back to where we started :-)
  
  
You are resuming multiple threads which all perform independent writes to disk, why would that be quicker than using the threadpool?
  
  
Threadpool code would be quicker to write, simpler to read, and I suspect it will probably execute faster too.  Have you compared the performance?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment31</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment31</guid><pubDate>Sun, 31 Oct 2010 11:13:15 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
Yes, the code to actually do the writes is in Lucene.NET
  
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment30</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment30</guid><pubDate>Sun, 31 Oct 2010 11:06:32 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>By that it sounds like you are saying that the thread doesn't have to "own the code" of doing the operation, is that correct?  Are you saying that your thread code calls a method on some other class which performs the IO?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment29</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment29</guid><pubDate>Sun, 31 Oct 2010 10:59:37 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
I don't do that. But that saves me each separate thread having to perform the IO op on the set of work that it has.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment28</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment28</guid><pubDate>Sun, 31 Oct 2010 10:57:13 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Okay, and how do you get multiple threads performing their own write operation to perform their IO as a single action?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment27</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment27</guid><pubDate>Sun, 31 Oct 2010 10:55:25 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Each thread write to its own directory
  
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment26</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment26</guid><pubDate>Sun, 31 Oct 2010 10:54:14 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>But do these individual threads write to disk, or does a single thread at the end perform a single write operation with all of the results?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment25</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment25</guid><pubDate>Sun, 31 Oct 2010 10:52:56 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
In memory computation is CHEAP.
  
The synchronization overhead on that is too high, just do it in a single thread.
  
The actual costs are in the IO, and they overshadow everything else.
  
  
This allows multiple workers to capture the waiting data and process that. Each of them does something else with it (actually, each of them is a separate index), but the idea is that we can capture multiple changes at one go, reducing IO costs.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment24</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment24</guid><pubDate>Sun, 31 Oct 2010 10:50:46 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>So multiple threads perform the updates in memory, and then when they are all completed the result is written to disk by a class that was waiting for the multiple threads to finish?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment23</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment23</guid><pubDate>Sun, 31 Oct 2010 10:42:24 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
By batch I mean that both doc A and doc B will be indexed at the same time, and will be written to disk on the same IO operation.
  
The difference is whatever you have 1 IO operation per batch or multiple.
  
  
By following this method, I can aggregate multiple changes and write them at a single action, not once per work item
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment22</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment22</guid><pubDate>Sun, 31 Oct 2010 10:40:28 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>I think it's the word "batch" you are losing me with.  By that do you mean that the jobs are performed in parallel or serial?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment21</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment21</guid><pubDate>Sun, 31 Oct 2010 10:33:46 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
  
The problem isn't the thread pool.
  
  
Let me see if I can explain.
  
  
We have:
  
* task 1 - index doc a
  
* task 2 - index doc b
  
  
If we run them via the thread pool, we would have to threat each of them as a separate operation
  
But if we run them via my code, we can batch both operations together. What this means is that our IO cost will go WAY down. 
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment20</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment20</guid><pubDate>Sun, 31 Oct 2010 10:30:02 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Well I'm no threading expert, but from what I recall of reading my threading book a while back the threadpool class is very well written and takes lots of things into account when balancing the load on your machine (based on number of processors, how long a job is taking to complete, etc) and is a preferable approach rather than waking up a specific number of threads at the same time.
  
  
Have you tried the ThreadPool and compared the performance?  If so, how did it compare?
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment19</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment19</guid><pubDate>Sun, 31 Oct 2010 10:25:11 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Peter,
  
No, not really. Because you would have to submit each independent job.
  
This way, you get to batch them, which is REALLY important from the point of view of performance.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment18</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment18</guid><pubDate>Sun, 31 Oct 2010 10:19:37 GMT</pubDate></item><item><title>Peter Morris commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Would it not be more simple to use the threadpool and queue some jobs along with a small packet of data for them to work on?
  
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment17</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment17</guid><pubDate>Sun, 31 Oct 2010 10:16:03 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Jeff,
  
Not really, no.
  
Work queues assume one item per task, in my case, I just want to wake those guys up, since they may have multiple tasks waiting for them.
  
It means that I don't have to do any work whatsoever for batching
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment16</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment16</guid><pubDate>Tue, 26 Oct 2010 18:21:25 GMT</pubDate></item><item><title>Jeff Cyr commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Your solution may work, but wouldn't it be a simpler approach to have a work queue in each worker thread?
  
  
Then when a change is made on your storage, you could simply queue an event on each worker queue.
  
  
Each worker thread could then wait when its queue is empty, then when an event is queued a simple Monitor.Pulse would be needed because each queue is only accessible by one worker thread.
  
  
Hope make sense.
  
  
Jeff
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment15</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment15</guid><pubDate>Tue, 26 Oct 2010 17:50:36 GMT</pubDate></item><item><title>configurator commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Ah right, of course. I had forgotten that's how wait works :\
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment14</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment14</guid><pubDate>Tue, 26 Oct 2010 16:42:00 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Imagine that I am just before this line:
  
  
if (MoreWorkToDo)
  
  
And then the Pulse happens. Using your code, I'll miss the notification.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment13</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment13</guid><pubDate>Tue, 26 Oct 2010 15:49:34 GMT</pubDate></item><item><title>Rafal commented on Synchronization primitives, MulticastAutoResetEvent</title><description>But why do you need to release threads that aren't waiting on the event? I was thinking about sth like this:
  
  
  
while(true)
  
{
  
 if (MoreWorkToDo)
  
 {
  
  DoTheWork();
  
 }
  
 else
  
 {
  
  Monitor.Wait();
  
 }
  
}
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment12</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment12</guid><pubDate>Tue, 26 Oct 2010 15:46:25 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Rafal,
  
Show me the code that will release multiple threads, including those not currently waiting on the event, to do so.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment11</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment11</guid><pubDate>Tue, 26 Oct 2010 15:15:45 GMT</pubDate></item><item><title>Rafal commented on Synchronization primitives, MulticastAutoResetEvent</title><description>can't you just check if there's more work to do in a loop and if not, hang on an event? This way Monitor.PulseAll would be sufficient.
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment10</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment10</guid><pubDate>Tue, 26 Oct 2010 15:09:48 GMT</pubDate></item><item><title>Ayende Rahien commented on Synchronization primitives, MulticastAutoResetEvent</title><description>Configurator,
  
That is how the Monitor works.
  
From the docs:
  
"The thread that currently owns the lock on the specified object invokes this method in order to release the object so that another thread can access it. The caller is blocked while waiting to reacquire the lock. This method is called when the caller needs to wait for a state change that will occur as a result of another thread's operations."
  
  
Note that there is a difference between Monitor.Enter and Monitor.Wait
</description><link>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment9</link><guid>http://ayende.com/4673/synchronization-primitives-multicastautoresetevent#comment9</guid><pubDate>Tue, 26 Oct 2010 13:13:26 GMT</pubDate></item></channel></rss>