﻿<?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>Jeff Cyr commented on Aysnc Read Challenge</title><description>Here is a version that use the Task Iterator provided in the TPL Samples:
  
[http://code.msdn.microsoft.com/ParExtSamples](http://code.msdn.microsoft.com/ParExtSamples)  
  
        public static Task
&lt;byte[]&gt;
 ReadAsync(Stream stream, int length)
  
        {
  
            byte[] buffer = new byte[length];
  
  
            return Task.Factory.Iterate(ReadBufferIterator(stream, buffer, length))
  
                               .ContinueWith(_ =&gt; buffer);
  
        }
  
  
        private static IEnumerable
&lt;task ReadBufferIterator(Stream stream, byte[] buffer, int length)
  
        {
  
            int offset = 0;
  
  
            while (offset != length)
  
            {
  
                Task
&lt;int readTask = stream.ReadAsync(buffer, offset, length - offset);
  
                yield return readTask;
  
                int readBytes = readTask.Result;
  
  
                if (readBytes == 0)
  
                    throw new IOException("Read 0 byte. The stream has been closed.");
  
  
                offset += readBytes;
  
            }
  
        }
  
  
        public static class StreamEx
  
        {
  
            public static Task
&lt;int ReadAsync(this Stream stream, byte[] buffer, int offset, int length)
  
            {
  
                return Task
&lt;int.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, length, null);
  
            }
  
        }
&gt;</description><link>http://ayende.com/4691/aysnc-read-challenge#comment18</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment18</guid><pubDate>Tue, 16 Nov 2010 23:11:01 GMT</pubDate></item><item><title>Demis Bellot commented on Aysnc Read Challenge</title><description>Hi @Mihailo
  
  
I was just saying that calling a delegate concurrently like this:
  
var ar = readBuffer.BeginInvoke(null, null);
  
  
Executes this on a ThreadPool thread.
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment17</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment17</guid><pubDate>Tue, 16 Nov 2010 20:22:16 GMT</pubDate></item><item><title>Mihailo commented on Aysnc Read Challenge</title><description>@Demis
  
  
We might be talking about different things here. Default implementation of Stream.BeginRead will execute:
  
  
return delegate2.BeginInvoke(buffer, offset, count, callback, state);
  
  
That's output from Reflector, so there will be new thread involved.
  
  
I'm just guessing that what you're referring to is my line:
  
var ar = readBuffer.BeginInvoke(null, null);
  
  
 Compiler will not create a new thread like I did there.
  
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment16</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment16</guid><pubDate>Tue, 16 Nov 2010 19:20:02 GMT</pubDate></item><item><title>Demis Bellot commented on Aysnc Read Challenge</title><description>@Mihailo
  
  
&gt;&gt;Mind though that you may still have code executed on a different thread, you may still have ThreadPool thread in background (or something similar). 
  
  
This is incorrect and is the main point of C# 5.0 async/await. No secret background thread spawned to achieve the behaviour. It's all done by the compiler wrapping your proceeding logic in a callback which is executed as part of a generated state machine (similar to how yield works):
  
  
"Whenever a task is "awaited", the remainder of the current method is signed up as a continuation of the task, and then control immediately returns to the caller. When the task completes, the continuation is invoked and the method starts up where it was before."
  
  
So no background threads - all your logic is executed on the same thread.
  
  
I recommend the following post for some more detailed info:
  
[blogs.msdn.com/.../asynchrony-in-c-5-part-one.aspx](http://blogs.msdn.com/b/ericlippert/archive/2010/10/28/asynchrony-in-c-5-part-one.aspx)  
  
As well as Anders talk on the subject:
  
[player.microsoftpdc.com/.../1b127a7d-300e-4385-...](http://player.microsoftpdc.com/Session/1b127a7d-300e-4385-af8e-ac747fee677a)  
  
- Demis
  
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment15</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment15</guid><pubDate>Tue, 16 Nov 2010 15:28:19 GMT</pubDate></item><item><title>Mihailo commented on Aysnc Read Challenge</title><description>@Demis Bellot
  
  
I'm not arguing that async/await isn't different, or better, that's why I said it will have nearly the same effect - in this particular example - not in general.
  
  
Mind though that you may still have code executed on a different thread, you may still have ThreadPool thread in background (or something similar). How do you think continuation is executed? How do you think callbacks are executed? Language additions are not making multi-threading magically disappear, they are just making it easier for us to develop and manage it.
  
  
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment14</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment14</guid><pubDate>Tue, 16 Nov 2010 14:50:43 GMT</pubDate></item><item><title>Demis Bellot commented on Aysnc Read Challenge</title><description>@Mihailo
  
  
I think you're missing the point. The C# 5.0 async features executes in the same thread, calling BeginInvoke/EndInvoke execute's the logic asynchronously on a ThreadPool thread. 
  
  
This is a very important difference and is the main purpose of async/await language features which allows you to easily develop composable async / non-blocking logic on the same thread. 
  
  
As soon as you introduce threading you introduce concurrency issues as well as additional overhead of context switching between threads.
  
  
- Demis
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment13</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment13</guid><pubDate>Tue, 16 Nov 2010 12:29:55 GMT</pubDate></item><item><title>Mihailo commented on Aysnc Read Challenge</title><description>@Harry Steinhilber
  
Thanks for that, second installment should have explained it but it doesn't work for me. It explains how it's made but it becomes too technical for my level of knowledge of C#5 features. If you look at Jon Skeet's post:
  
  
[msmvps.com/.../...-investigating-control-flow.aspx](http://msmvps.com/blogs/jon_skeet/archive/2010/10/30/c-5-async-investigating-control-flow.aspx)  
  
He explains it like to an 8 year old. And yes, you're correct, it's a bit different, but to the caller of the ReadBuffer method. The part of the code I laid out is a bit of oversimplification and to work the same way it would with async and awit it needs collaboration from method caller.
  
  
I believe this code will have the same effect as C#5 version:
  
  
private static Tuple
&lt;byte[],&gt;
 ReadBuffer(Stream s, int bufferSize)
  
 var buffer = new byte[bufferSize];
  
 int read = -1;
  
 int start = 0;
  
 while(read != 0)
  
 {
  
  var ar = stream.BeginRead(buffer, start, buffer.Length - start, null, null);
  
  read = stream.EndRead(ar)
  
  start += read;
  
 }
  
 return Tuple.Create(buffer, start);
  
}
  
  
  
Func
&lt;stream,&gt;
&gt; readBuffer = (s, bufferSize) =&gt; ReadBuffer(s, bufferSize);
  
var ar = readBuffer.BeginInvoke(null, null);
  
... do something ...
  
var data = readBuffer.EndInvoke(ar);
  
  
I understand this seems to be uglier, especially for the caller, but that's probably reason why the new language features are introduced. Also, I understand this code is not 1-to-1 equivalent, I'm just saying it will have the same effect for the example given by Oren.
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment12</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment12</guid><pubDate>Tue, 16 Nov 2010 11:17:43 GMT</pubDate></item><item><title>Harry Steinhilber commented on Aysnc Read Challenge</title><description>@Mihailo,
  
The C#5 code will not block on await. If a result is immediately available, it will continue, but if it is not, it signs the rest of the method up in a continuation and returns to the caller. The continuation will be called when the result becomes available. See Eric Lippert's excellent series of explanations.
  
  
[blogs.msdn.com/.../c_2300_+5-0/](http://blogs.msdn.com/b/ericlippert/archive/tags/c_2300_+5-0/)</description><link>http://ayende.com/4691/aysnc-read-challenge#comment11</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment11</guid><pubDate>Mon, 15 Nov 2010 22:10:42 GMT</pubDate></item><item><title>Kiran commented on Aysnc Read Challenge</title><description>Using Jeff Richter's AsyncEnumerator class
  
  
void Main()
  
{
  
	var ae = new AsyncEnumerator();
  
	ae.EndExecute(ae.BeginExecute
  
					(ProcessFile(ae, @"filepath", 8192), null));
  
}
  
  
private static IEnumerator
&lt;int32 ProcessFile(AsyncEnumerator ae, string pathName, Int32 bufferSize)
  
{
  
	using(FileStream fs = 
  
			new FileStream(pathName, FileMode.Open, FileAccess.Read, 
  
			FileShare.Read, bufferSize, FileOptions.Asynchronous))
  
	{
  
		Byte[] data = new Byte[fs.Length];
  
		fs.BeginRead(data, 0, data.Length, ae.End(), null);
  
		yield return 1;
  
  
  
		fs.EndRead(ae.DequeueAsyncResult());
  
		Console.WriteLine(UTF8Encoding.UTF8.GetString(data));
  
	}
  
}
&gt;</description><link>http://ayende.com/4691/aysnc-read-challenge#comment10</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment10</guid><pubDate>Mon, 15 Nov 2010 18:50:25 GMT</pubDate></item><item><title>Mihailo commented on Aysnc Read Challenge</title><description>I might be wrong but isn't  C#5 version pretty much the same as:
  
  
var buffer = new byte[bufferSize];
  
int read = -1;
  
int start = 0;
  
while(read != 0)
  
{
  
   var ar = stream.BeginRead(buffer, start, buffer.Length - start, null, null);
  
   read = stream.EndRead(ar)
  
   start += read;
  
}
  
  
Code will block on await, here it will block on EndRead, no?
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment9</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment9</guid><pubDate>Mon, 15 Nov 2010 16:27:41 GMT</pubDate></item><item><title>Ajai Shankar commented on Aysnc Read Challenge</title><description>You might want to look at this too Ayende
  
  
[http://easyasync.codeplex.com/](http://easyasync.codeplex.com/)  
  
This was inspired over 6 years back from the good old state threads library.
  
  
Now we have async CTP, node.js, torando all dealing with non blocking io...
  
  
Also do see the links at bottom...
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment8</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment8</guid><pubDate>Mon, 15 Nov 2010 02:05:08 GMT</pubDate></item><item><title>Paul Stovell commented on Aysnc Read Challenge</title><description>ThreadPool.QueueUserWorkItem(
  
   () =&gt; {
  
      // The code you wrote above ;)
  
});
  
  
Except you won't get the benefits of IOCP. 
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment7</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment7</guid><pubDate>Mon, 15 Nov 2010 00:40:03 GMT</pubDate></item><item><title>Ollie commented on Aysnc Read Challenge</title><description>+1 Omar
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment6</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment6</guid><pubDate>Sun, 14 Nov 2010 22:17:07 GMT</pubDate></item><item><title>anon commented on Aysnc Read Challenge</title><description>search for
  
"Sequential Asynchronous Workflows in Silverlight using Coroutines"
  
or
  
"Rob Eisenburg's MVVM presentation from MIX10" which introduces that idea.
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment5</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment5</guid><pubDate>Sun, 14 Nov 2010 22:00:02 GMT</pubDate></item><item><title>Omer Mor commented on Aysnc Read Challenge</title><description>Here is a version that uses Rx for comparison:
  
[http://pastebin.com/ay2Ncnbg](http://pastebin.com/ay2Ncnbg)  
  
For more context, you should read the following blog post (from which the code was copied):
  
[blogs.msdn.com/.../...ystem-io-stream-reading.aspx](http://blogs.msdn.com/b/jeffva/archive/2010/07/23/rx-on-the-server-part-1-of-n-asynchronous-system-io-stream-reading.aspx)</description><link>http://ayende.com/4691/aysnc-read-challenge#comment4</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment4</guid><pubDate>Sun, 14 Nov 2010 18:11:38 GMT</pubDate></item><item><title>g commented on Aysnc Read Challenge</title><description>The C# 5.0 async usage looks so ... ugly to me. I cannot articulate why though, it just seems rather esoteric.
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment3</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment3</guid><pubDate>Sun, 14 Nov 2010 16:19:51 GMT</pubDate></item><item><title>Daniel Grunwald commented on Aysnc Read Challenge</title><description>I've had to do something like that years ago.
  
I don't have that code anymore, but I think my solution looked similar to this (sorry, no TPL there):
  
  
class BufferReader
  
{
  
	byte[] buffer;
  
	int pos;
  
	Stream stream;
  
	Exception exception;
  
  
	public BufferReader(Stream stream, int bufferSize)
  
	{
  
		this.stream = stream;
  
		this.buffer = new byte[bufferSize];
  
	}
  
  
	public void BeginRead()
  
	{
  
		stream.BeginRead(buffer, pos, buffer.Length - pos, Callback, null);
  
	}
  
  
	void Callback(IAsyncResult r)
  
	{
  
		int read;
  
		try {
  
			read = stream.EndRead(r);
  
		} catch (Exception ex) {
  
			exception = ex;
  
			if (ReadError != null)
  
				ReadError(this, EventArgs.Empty);
  
			return;
  
		}
  
		if (read == 0) {
  
			if (FinishedReading != null)
  
				FinishedReading(this, EventArgs.Empty);
  
		} else {
  
			pos += read;
  
			BeginRead();
  
		}
  
	}
  
  
	public event EventHandler FinishedReading;
  
	public event EventHandler ReadError;
  
  
	// + properties that allow the caller to access buffer,pos,exception
  
}
  
  
Usage of that class: create an instance, attach event handlers, then call BeginRead().
  
  
BTW, your code is wrong, you should use «buffer.Length - start» instead of «buffer.Length - 1».
</description><link>http://ayende.com/4691/aysnc-read-challenge#comment2</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment2</guid><pubDate>Sun, 14 Nov 2010 12:32:19 GMT</pubDate></item><item><title>Duarte Nunes commented on Aysnc Read Challenge</title><description>public static Task
&lt;tuple&lt;byte[],&gt;
&gt; ReadBuffer(Stream s, int bufferSize)
  
{
  
    var buffer = new byte[bufferSize];
  
    int start = 0;
  
  
    var tcs = new TaskCompletionSource
&lt;tuple&lt;byte[],&gt;
&gt;();
  
  
    Action
&lt;task&lt;int&gt; cont = null;
  
    cont = t =&gt;
  
    {
  
        if (t != null)
  
        {
  
            if (t.Exception != null)
  
            {
  
                tcs.SetException(t.Exception);
  
                return;
  
            }
  
            if (t.Result == 0)
  
            {
  
                tcs.SetResult(Tuple.Create(buffer, start));
  
                return;
  
            }
  
  
            start += t.Result;
  
        }
  
  
        Task.Factory.FromAsync
&lt;byte[],&gt;
(
  
        s.BeginRead,
  
        s.EndRead,
  
        buffer,
  
        start,
  
        buffer.Length - 1,
  
        null).ContinueWith(cont);
  
    };
  
  
    cont(null);
  
  
    return tcs.Task;
  
}
&gt;</description><link>http://ayende.com/4691/aysnc-read-challenge#comment1</link><guid>http://ayende.com/4691/aysnc-read-challenge#comment1</guid><pubDate>Sun, 14 Nov 2010 12:19:19 GMT</pubDate></item></channel></rss>