Calling an asynchronous method serially?

If you wrap this in a helper class, you could make the helper "synchronize" your values.

Up vote 1 down vote favorite 2 share g+ share fb share tw.

I have the following (simplified) asynchronous method: void Transform(X x, Action resultCallback) {...} and what I want to do is transform a list of Xs into a list of Ys. The problem is that even though the Transform method is asynchronous, it has to be called serially (i.e. I have to wait for the callback before calling it with the next value).

Is there any way to do this elegantly? (I'm on . Net 4.0) I'm guessing there might be some way to do it with continuation passing... UPDATE I forgot to specify that I don't want to block the calling (GUI) thread.

C# .net winforms asynchronous link|improve this question edited Oct 12 '10 at 8:06 asked Oct 11 '10 at 18:50Benjol9,76333386 71% accept rate.

– arootbeer Oct 11 '10 at 18:55 @arootbeer, yes. – Benjol Oct 11 '10 at 19:35.

If you wrap this in a helper class, you could make the helper "synchronize" your values: public class AsyncWrapper { ManualResetEvent mre; private Y result; public Y Transform(X x, YourClass yourClass) { mre = new ManualResetEvent(false); result = default(Y); yourClass. Transform(x, this. OnComplete); mre.WaitOne(); return result; } void OnComplete(Y y) { result = y; mre.Set(); } } You could then use this like: // instance your class with the Transform operation YourClass yourClass = new YourClass(); AsyncWrapper wrapper = new AsyncWrapper(); foreach(X x in theXCollection) { Y result = wrapper.

Transform(x, yourClass); // Do something with result } Edit: Since you say you're trying to do this to keep everything running on a background thread, you can use my code above, and do: // Start "throbber" Task.Factory. StartNew () => { // instance your class with the Transform operation YourClass yourClass = new YourClass(); AsyncWrapper wrapper = new AsyncWrapper(); foreach(X x in theXCollection) { Y result = wrapper. Transform(x, yourClass); // Do something with result } }).

ContinueWith( t => { // Stop Throbber }, TaskScheduler. FromCurrentSynchronizationContext()); This will start the entire (now synchronous) process on a background thread, and disable your "throbber" (from comment) on the UI thread once it completes. If you control all of this code, you can make your Transform process synchronous from the start, and just move it into a background thread as above, avoiding the need for the wrapper.

Thanks for the rapid answer, I'm not in the office right now, but I'll be trying it tomorrow! Just one question - the whole reason this .. transform is on another thread is so that the 'throbber' keeps turning (winforms), does the WaitOne block that? – Benjol Oct 11 '10 at 19:06 @Benjol: Yes - making it synchronous will, by definition, block the thread on which you call it.

You can move your entire process to a background thread, though (ie: process the entire loop on a background thread serially)... – Reed Copsey Oct 11 '10 at 19:12 @Benjol: I added another section to this - hopefully to show you what I meant ... – Reed Copsey Oct 11 '10 at 20:10 Thanks @Reed. I'm also toying with another solution (see my answer). Haven't decided which way to go yet, but you get the tick :) – Benjol Oct 11 '10 at 8:04.

As I hinted in my question, I wondered about a solution using continuation-passing. The following extension methods allow me to have a fairly 'pretty' usage: public static class Extensions { //Using an asynchronous selector, calculate transform for // input list and callback with result when finished public static void AsyncSelect(this List list, Action> selector, Action> callback) { var listOut = new List(); list. AsyncSelectImpl(listOut, selector, callback); } //internal implementation - hides the creation of the output list private static void AsyncSelectImpl(this List listIn, List listOut, Action> selector, Action> callback) { if(listIn.

Count == 0) { callback(listOut); //finished (also if initial list was empty) } else { //get first item from list, recurse with rest of list var first = listIn0; var rest = listIn. Skip(1).ToList(); selector(first, result => { listOut. Add(result); rest.

AsyncSelectImpl(listOut, selector, callback); }); } } } On the calling side, this results in: (...) //(For a Transform which performs int -> string) Throbber.Start(); inList. AsyncSelect(Transform, WhenDone); } private void WhenDone(List outList) { Throbber.Stop(); //do something with outList } One obvious limitation is stack overflow - for my purposes, that won't be a problem (I'm in the tens of items, not thousands). Any other glaring bloopers in the comments please!

I flirted briefly with trying to do this on an IEnumerable (built-in state machine), but I don't think it's possible to do 'downwind' async. Tomas Petricek does 'upwind' async here – Benjol Oct 12 '10 at 8:26.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions