in a discussion on asynchronous programming in C# the author speaks matter of factly of "puppet tasks". It shows up in various places on stack overflow. But it is only used, never explained. Here are some examples of where it is mentioned here, here, here, and in the book Async in C# 5.0.
What should I make of puppet tasks or puppets in programming? Is it indicating some mockup? A task wrapper or what?
Thank you.
Before the creation of Task in C#, Microsoft had implemented other means of creating asynchronous events. One was the Event-Asynchronous Pattern (EAP), where a callback method is fired when the asynchronous event finishes. Another is the Asynchronous Programming Model (APM) which uses IAsyncResult and Begin/End style methods.
When the Task-based Asynchronous Pattern (TAP) was added, Microsoft made a concerted effort to add Task based versions of all of the async APIs in the BCL. However, they couldn't do everything, and on top of that, many third-party libraries were already out there using either EAP or APM. At the same time though, they realized the value of using the TAP and the value async and await bring. As a result, they created the TaskCompletionSource. This serves as a wrapper to make non-TAP APIs work with TAP. Essentially, you create what many refer to as a puppet task. This is a task that really only exists to turn an EAP or APM (or other async pattern) method into a TAP method. For example, say you have a class, DownloadFile. This class fires a DownloadComplete event when the file is done. Normally you'd do something like:
DownloadFile myfile = new DownloadFile();
myfile.Complete += SomeMethodToHandleCompletion;
myfile.Download();
Then, at some point your method fires. That's great, but we want tasks. So what you could do is something like:
public Task<string> DownloadFileAsync(string url)
{
var tcs = new TaskCompletionSource<string>();
DownloadFile myfile = new DownloadFile(url);
myfile.Complete += (theData) =>
{
tcs.SetResult(theData);
};
return tcs.Task;
}
That's a simplistic example since I'm not handling exceptions or anything, but essentially, now I've turned an event handler (EAP) into something I can use with async/await by creating a "puppet task" that simply does the bidding of the event. When the event finishes, we simply say "hey the Task is done too". As a result, the following works:
string downloadedFile = await DownloadFileAsync("http://www.some.url.example");
Related
I'm trying to understand how and when to use async programming and got to I/O bound operations, but I don't understand them. I want to implement them from scratch. How can I do that?
Consider the example below which is synchronous:
private void DownloadBigImage() {
var url = "https://cosmos-magazine.imgix.net/file/spina/photo/14402/180322-Steve-Full.jpg";
new WebClient().DownloadFile(url, "image.jpg");
}
How do I implement the async version by only having the normal synchronous method DownloadBigImage without using Task.Run since that will use a thread from the thread pool only for waiting - that's just being wasteful!
Also do not use the special method that's already async! This is the purpose of this question: how do I make it myself without relying on methods which are already async? So, NO things like:
await new WebClient().DownloadFileTaskAsync(url, "image.jpg");
Examples and documentation available are very lacking in this regard. I found only this:
https://learn.microsoft.com/en-us/dotnet/standard/async-in-depth
which says:
The call to GetStringAsync() calls through lower-level .NET libraries (perhaps calling other async methods) until it reaches a P/Invoke interop call into a native networking library. The native library may subsequently call into a System API call (such as write() to a socket on Linux). A task object will be created at the native/managed boundary, possibly using TaskCompletionSource. The task object will be passed up through the layers, possibly operated on or directly returned, eventually returned to the initial caller.
Basically I have to use a "P/Invoke interop call into a native networking library"... but how?
This is a great question which really isn't explained well in most texts about C# and async.
I searched for this for ages thinking I could and should maybe be implementing my own async I/O methods. If a method/library I was using didn't have async methods I thought I should somehow wrap these functions in code that made them asynchronous. It turns out that this isn't really feasible for most programmers. Yes, you can spawn a new thread using Thread.Start(() => {...}) and that does make your code asynchronous, but it also creates a new thread which is an expensive overhead for asynchronous operations. It can certainly free up your UI thread to ensure your app stays responsive, but it doesn't create a truly async operation the way that HttpClient.GetAsync() is a truly asynchronous operation.
This is because async methods in the .net libraries use something called "standard P/Invoke asynchronous I/O system in .NET" to call low level OS code that doesn't require a dedicated CPU thread while doing outbound IO (networking or storage). It actually doesn't dedicate a thread to its work and signals the .net runtime when it's done doing its stuff.
I'm not familiar with the details but this knowledge is enough to free me from trying to implement async I/O and make me focus on using the async methods already present in the .net libraries (such as HttpClient.GetAsync()). More interesting info can be found here (Microsoft async deep dive) and a nice description by Stephen Cleary here
I think this is a very interesting question and a fun learning exercise.
Fundamentally, you cannot use any existing API that is synchronous. Once it's synchronous there is no way to turn it truly asynchronous. You correctly identified that Task.Run and it's equivalents are not a solution.
If you refuse to call any async .NET API then you need to use PInvoke to call native APIs. This means that you need to call the WinHTTP API or use sockets directly. This is possible but I don't have the experience to guide you.
Rather, you can use async managed sockets to implement an async HTTP download.
Start with the synchronous code (this is a raw sketch):
using (var s = new Socket(...))
{
s.Connect(...);
s.Send(GetHttpRequestBytes());
var response = new StreamReader(new NetworkStream(s)).ReadToEnd();
}
This very roughly gets you an HTTP response as a string.
You can easily make this truly async by using await.
using (var s = new Socket(...))
{
await s.ConnectAsync(...);
await s.SendAsync(GetHttpRequestBytes());
var response = await new StreamReader(new NetworkStream(s)).ReadToEndAsync();
}
If you consider await cheating with respect to your exercise goals you would need to write this using callbacks. This is awful so I'm just going to write the connect part:
var s = new Socket(...)
s.BeginConnect(..., ar => {
//perform next steps here
}, null);
Again, this code is very raw but it shows the principle. Instead of waiting for an IO to complete (which happens implicitly inside of Connect) you register a callback that is called when the IO is done. That way your main thread continues to run. This turns your code into spaghetti.
You need to write safe disposal with callbacks. This is a problem because exception handling cannot span callbacks. Also, you likely need to write a read loop if you don't want to rely on the framework to do that. Async loops can be mind bending.
TLDR: Generally you can by using TaskCompletionSource.
If you only have blocking calls available then you cannot do this. But usually there are "old" asynchronous methods that do not use async nor Task, but rely instead on callbacks. In that case you can use a TaskCompletionSource to both create a Task that can be returned, and use it to set the Task to completed when the callback returns.
Example using the old .Net Framework 3.0 methods in WebClient (but programmed in later .Net that has Task):
public Task DownloadCallbackToAsync(string url, string filename)
{
using (var client = new WebClient())
{
TaskCompletionSource taskCreator = new TaskCompletionSource();
client.DownloadFileCompleted += (sender, args) => taskCreator.SetResult();
client.DownloadFileAsync(url, filename);
return taskCreator.Task;
}
}
Here you will imidiately initiate the call and return a Task. If you await the Task in the calling method you will not continue until the callback (DownloadFileCompleted) has occurred.
Note that this method itself is not async as it does not need to await a Task.
Create a new task that executes the synchronous code. The task will be executed by a thread of the threadpool.
private async Task DownloadBigImage()
{
await Task.Run(()=>
{
var url = "https://cosmos-magazine.imgix.net/file/spina/photo/14402/180322-Steve-Full.jpg";
new WebClient().DownloadFile(url, "image.jpg");
});
}
I’m using MvvmCross and the AsyncEx library within a Windows 10 (UWP) App.
In a ViewModel, I have an INotifyTaskCompletion property (1) which is wired-up to an Async method in the ViewModel (2)
In (2), I call an Async library method which:
Checks a local cache
Downloads data asynchronously
Adds the data to the cache
The caching code cannot be made asynchronous and so the library method contains both blocking and asynchronous code.
Q. What’s the best way to prevent blocking the UI thread?
I understand from Stephen Cleary to not to block in asynchronous code and not use Task.Run in library methods. So do I have to….
Move the caching calls into (2) e.g.
Use Task.Run (to check the cache)
Call the library method asynchronously
Use Task.Run again (to cache the data)?
Is there a better way?
If you have completely synchronous code which you can't change to make it return an awaitable, and want to make it asynchronous, then yes, your only choice if you want to use async/await is to use Task.Run().
Something like:
public async Task<T> MyMethod()
{
T result = await Task.Run(() => CheckCacheOnSyncMethodICantChange());
if(result != null)
{
result = await MyLibraryMethodThatReturnsATask();
await Task.Run(() => AddToCacheOnSyncMethodICantChange(result));
}
return result;
}
Should be ok.
I would like to read data from a stream (serial, tcp, whatever) asynchronously and trigger events to notify other components.
Following is pseudo code, assuming "stream" is a valid stream.
public class Reader {
private _stream;
private _buffer = new bytes[4096];
public event Action<byte[], int> DataRecieved;
public async void StartReading() {
while (true) {
var nbytes = await _stream.ReadAsync(_buffer, 0, _buffer.Length);
if (nbytes == 0)
return;
var handlers = DataRecieved;
if (handlers != null)
DataRecieved(_buffer, nbytes);
}
}
}
And the caller part:
var r = new Reader();
r.OnDataRecieved += myHandler;
r.StartReading();
I'm not sure doing something like this is a good idea. I read that using asynchonous void functions is not a good idea, but here I don't want caller to wait for the result, I want to notify it when some data is available.
What's the good way to do something like that ?
void async is only considered to be used for GUI event handlers. In WinForms, events have all delegate-types of type void. Usually, you want, when using async , notify your caller when you have finished - in an asynchronous way. The .NET message-loop is considered the exception here, since you have no different possibility to use async.
In your case, the async/await keywords won't make much sense. I'd recommend to invoke your method using a Task or the ThreadPool (or BackgroundWorker).
You do not have a long running task on which you want to react in a asynchronous manner, but a parallel background-task, which should be used as such.
The idea of async/await is that the caller of a method continues after the method invocation and may execute code inside the method behind an await later. But that requires you to use await in the calling-method, which would block your main-thread.
Long story short: You have no other chance as using a second thread and use thread-synchronization.
Invoke is nothing else as placing a delegate in a queue which the message-loop reads and executes. In your case, you could do something similar: Take the read data, like the byte[] and put that in a queue (via the event). And whenever your main-thread desires to do some work, he grabs an item from the queue.
That is one option. The best solution for this issue depends strongly on your application, and as far as you didn't tell us more details about the design, I can't recommend the best way. But async/await won't be it. Definitely.
Make the method return Task to avoid async void. You can ignore that task if you want but eventually you probably want to wait for it to complete.
Also handle errors. Right now they are thrown away and the reading stops silently. You will never find bugs this way.
Wrap everything in Task.Run to make sure that this async method really runs completely asynchronously. Right now if each await completes right away this method will never return or not return in a long time. Don't risk that. Alternatively you can place await Task.Yield(); at the first line of the method.
My knowledge of how async/await methods are run and on what thread is a little hazy. I would like to block a method until an event is fired. To do this I tried using the ManualResetEvent however this blocks every call to the async method until the last waitHandle.Set( ) is called at which point all async methods complete (or so it seems).
I need a way to block async calls individually as I'm trying to convert the event based asynchronous approach to a Task based async/await one.
How can/should I go about it?
Update:
Based on the information provided by Stephen and Noseratio, I have now changed my asynchronous methods to something a long the lines of this:
public async Task<IEnumerable<CustomerNoteInfo>> LoadClientNotesAsync(int id)
{
return await _session.InvokeOperationAsync((client) =>
{
var tcs = new TaskCompletionSource<IEnumerable<CustomerNoteInfo>>( );
client.GetCustomerNotesCompleted += (sender, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else tcs.TrySetResult(e.Result);
};
client.GetCustomerNotesAsync(id);
return tcs.Task;
}).Unwrap( );
}
I'm sure this is going to look ugly to everyone who has ever done any async/await Task based programming, but am I on the right track for this? It seems to have fixed the problem I was having with the manual reset event and I can now run this method multiple times asynchronously. :)
My knowledge of how async/await methods are run and on what thread is a little hazy.
I recommend you start with my async intro, which covers the keywords and how they determine which thread to use.
I'm trying to convert the event based asynchronous approach to a Task based async/await one.
The MSDN documentation on this is quite good.
You do not need to block an async method; just create a TAP (Task-based) wrapper for the EAP (method/event pair). Then you can just call your TAP method and await the returned task.
I have the following asynchronous code:
public async Task<List<PreprocessingTaskResult>> Preprocess(Action onPreprocessingTaskFinished)
{
var preprocessingTasks = BuildPreprocessingTasks();
var preprocessingTaskResults = new List<PreprocessingTaskResult>();
while (preprocessingTasks.Count > 0)
{
//Wait till at least one task is completed
await TaskEx.WhenAny(preprocessingTasks.ToArray());
onPreprocessingTaskFinished();
}
return
}
And the asynchronous usage code
var preprocessingTaskResults = await Preprocess(someAction);
For some cases I need to call it in synchronous way. For simpler cases (when async method returns just a task) I used to do the following:
var someTask = AsyncMethod();
Task.Wait(someTask);
But I am confused how I should implement it here.
A task's Result property will block until the task completes and then return its result:
List<PreprocessingTaskResult> result = Preprocess(someAction).Result;
http://msdn.microsoft.com/en-us/library/dd321468(v=vs.110).aspx
There is no easy way to call asynchronous code synchronously. Stephen Toub covers some various approaches here but there is no approach that works in all situations.
The best solution is to change the synchronous calling code to be asynchronous. With the advent of Microsoft.Bcl.Async and recent releases of Xamarin, asynchronous code is now supported on .NET 4.0 (and higher), Windows Phone 7.1 (and higher), Windows Store, Silverlight 4 (and higher), iOS/MonoTouch, Android/MonoDroid, and portable class libraries for any mix of those platforms.
So there's very little reason these days not to use async.
But if you absolutely need a synchronous API, then the best solution is to make it synchronous all the way. If you do need both asynchronous and synchronous APIs, this will cause code duplication which is unfortunate but it is the best solution at this time.