I have a search application that takes some time (10 to 15 seconds) to return results for some queries. Often you have to have several simultaneous requests to get the same information. Be that as it may, I have to process them myself, which leads to quite unnecessary processing.
I came up with a design that should allow me to avoid unnecessary processing, but there is one lingering problem.
Each request has a key that identifies the requested data. I maintain a query dictionary, with a query key. The request object has some status information and WaitHandlewhich is used to wait for results.
When the client calls my method Search, the code checks the dictionary to see if this request already exists for this key. If so, the client is just waiting WaitHandle. If the request does not exist, I create it, add it to the dictionary and issue an asynchronous call to get the information. Again, the code expects an event.
When the asynchronous process receives the results, it updates the request object, removes the request from the dictionary, and then signals the event.
It all works great. In addition, I do not know when to delete the request object. That is, since I do not know when the last client uses it, I can not call Disposeon it. I need to wait for the garbage collector to come and clean.
Here is the code:
class SearchRequest: IDisposable
{
public readonly string RequestKey;
public string Results { get; set; }
public ManualResetEvent WaitEvent { get; private set; }
public SearchRequest(string key)
{
RequestKey = key;
WaitEvent = new ManualResetEvent(false);
}
public void Dispose()
{
WaitEvent.Dispose();
GC.SuppressFinalize(this);
}
}
ConcurrentDictionary<string, SearchRequest> Requests = new ConcurrentDictionary<string, SearchRequest>();
string Search(string key)
{
SearchRequest req;
bool addedNew = false;
req = Requests.GetOrAdd(key, (s) =>
{
var r = new SearchRequest(s);
Console.WriteLine("Added new request with key {0}", key);
addedNew = true;
return r;
});
if (addedNew)
{
ThreadPool.QueueUserWorkItem((obj) =>
{
req.Results = DoSearch(req.RequestKey);
SearchRequest trash;
Requests.TryRemove(req.RequestKey, out trash);
req.WaitEvent.Set();
});
}
Console.WriteLine("Waiting for results from request with key {0}", key);
req.WaitEvent.WaitOne();
return req.Results;
}
, , . , , . :
- A , Thread 2 .
- Thread B .
- C , , .
- Thread B , .
- Thread , .
- C,
WaitOne, .
- , "" Dispose, Thread A . Thread C , WaitHandle.
, , - ( ConcurrentDictionary ), . , .
WaitHandle . , , . .
, , , , , GC . , ? , , GC, Dispose, .
? ? , ?