Skip to content

Instantly share code, notes, and snippets.

@dschenkelman
Created May 9, 2014 04:10
Show Gist options
  • Save dschenkelman/af129e88ebb996f2a152 to your computer and use it in GitHub Desktop.
Save dschenkelman/af129e88ebb996f2a152 to your computer and use it in GitHub Desktop.
Asynchronous I/O in C#: Why tasks (a.k.a. promises, futures)?
class ProgramWithAPM : IRunnable
{
private int pending;
private readonly object lockObject;
public ProgramWithAPM()
{
this.pending = 0;
this.lockObject = new object();
}
public void Run()
{
var schenkelmanRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://blogs.southworks.net/dschenkelman"));
var convertiRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://blogs.southworks.net/mconverti"));
this.pending = 2;
schenkelmanRequest.BeginGetResponse(ar =>
{
var response = (HttpWebResponse)schenkelmanRequest.EndGetResponse(ar);
WriteContent(response);
}, schenkelmanRequest);
convertiRequest.BeginGetResponse(ar =>
{
var response = (HttpWebResponse)convertiRequest.EndGetResponse(ar);
WriteContent(response);
}, convertiRequest);
}
private void WriteContent(HttpWebResponse response)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
lock (this.lockObject)
{
Console.WriteLine(content.Substring(0, 300));
this.pending--;
if (this.pending == 0)
{
Console.WriteLine("Downloads finished");
Program.ResetEvent.Set();
}
}
}
}
}
class ProgramWithAPM : IRunnable
{
public void Run()
{
var schenkelmanRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://blogs.southworks.net/dschenkelman"));
var convertiRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://blogs.southworks.net/mconverti"));
var schenkelmanTask = schenkelmanRequest.CustomGetResponseStreamAsync().ContinueWith(t =>
{
using (var reader = new StreamReader(t.Result))
{
var content = reader.ReadToEnd();
Console.WriteLine(content.Substring(0, 300));
}
});
var convertiTask = convertiRequest.CustomGetResponseStreamAsync().ContinueWith(t =>
{
using (var reader = new StreamReader(t.Result))
{
var content = reader.ReadToEnd();
Console.WriteLine(content.Substring(0, 300));
}
});
Task.WhenAll(convertiTask, schenkelmanTask).ContinueWith(t =>
{
Console.WriteLine("Downloads finished");
Program.ResetEvent.Set();
});
}
}
public class ProgramWithTasksAndCancellation : IRunnable
{
public void Run()
{
var client = new HttpClient();
var cts = new CancellationTokenSource();
var convertiTask = client.GetAsync(new Uri("http://blogs.southworks.net/mconverti"), cts.Token);
convertiTask.ContinueWith(t => Console.WriteLine("Converti completed"), TaskContinuationOptions.NotOnCanceled);
var schenkelmanTask = client.GetAsync(new Uri("http://blogs.southworks.net/dschenkelman"), cts.Token);
schenkelmanTask.ContinueWith(t => Console.WriteLine("Schenkelman completed"), TaskContinuationOptions.NotOnCanceled);
Task.WhenAny(convertiTask, schenkelmanTask).ContinueWith(t =>
{
cts.Cancel();
var firstTaskThatCompleted = (t.Result);
firstTaskThatCompleted.Result.Content.ReadAsStringAsync().ContinueWith(t2 =>
{
Console.WriteLine(t2.Result.Substring(0, 300));
Console.WriteLine("Downloads finished");
Program.ResetEvent.Set();
});
});
}
}
public class ProgramWithEvents : IRunnable
{
private int pending;
private readonly object lockObject;
public ProgramWithEvents()
{
this.pending = 0;
this.lockObject = new object();
}
public void Run()
{
var convertiClient = new WebClient();
var schenkelmanClient = new WebClient();
convertiClient.OpenReadCompleted += (sender, eventArgs) => this.WriteContent(eventArgs.Result);
schenkelmanClient.OpenReadCompleted += (sender, eventArgs) => this.WriteContent(eventArgs.Result);
this.pending = 2;
schenkelmanClient.OpenReadAsync(new Uri("http://blogs.southworks.net/dschenkelman"));
convertiClient.OpenReadAsync(new Uri("http://blogs.southworks.net/mconverti"));
}
private void WriteContent(Stream stream)
{
using (var reader = new StreamReader(stream))
{
var content = reader.ReadToEnd();
lock (lockObject)
{
Console.WriteLine(content.Substring(0, 300));
this.pending--;
if (this.pending == 0)
{
Console.WriteLine("Downloads finished");
Program.ResetEvent.Set();
}
}
}
}
}
public static class TaskExtensions
{
public static Task<Stream> GetResponseAsync(this HttpWebRequest webRequest)
{
var tcs = new TaskCompletionSource<Stream>();
webRequest.BeginGetResponse(ar =>
{
var response = (HttpWebResponse)webRequest.EndGetResponse(ar);
tcs.SetResult(response.GetResponseStream());
}, webRequest);
return tcs.Task;
}
public static Task<Stream> TaskBasedOpenReadAsync(this WebClient webClient, Uri uri)
{
var tcs = new TaskCompletionSource<Stream>();
OpenReadCompletedEventHandler callback = null;
callback = (sender, args) =>
{
tcs.SetResult(args.Result);
webClient.OpenReadCompleted -= callback;
};
webClient.OpenReadCompleted += callback;
webClient.OpenReadAsync(uri);
return tcs.Task;
}
}
class Program
{
public static AutoResetEvent ResetEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
// decide which asynchronous proposal to use
Run(new ProgramWithAPM());
}
static void Run(IRunnable runnable)
{
runnable.Run();
ResetEvent.WaitOne();
Console.ReadLine();
}
}
class ProgramWithTasks : IRunnable
{
public void Run()
{
var client = new HttpClient();
var convertiTask = client.GetStreamAsync(new Uri("http://blogs.southworks.net/mconverti")).ContinueWith(t =>
{
using (var reader = new StreamReader(t.Result))
{
var content = reader.ReadToEnd();
Console.WriteLine(content.Substring(0, 300));
}
});
var schenkelmanTask = client.GetStreamAsync(new Uri("http://blogs.southworks.net/dschenkelman")).ContinueWith(t =>
{
using (var reader = new StreamReader(t.Result))
{
var content = reader.ReadToEnd();
Console.WriteLine(content.Substring(0, 300));
}
});
Task.WhenAll(convertiTask, schenkelmanTask).ContinueWith(t =>
{
Console.WriteLine("Downloads finished");
Program.ResetEvent.Set();
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment