How could I call the onCompleteCallBack method on the same thread the SomeAsyncMethod was called ?
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current thread
/* var ThisThread = Thread.CurrentThread. */
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
/* ThisThread.Invoke("some result"); */
});
}
While you can't guarantee you callback will be called on the same thread, you can guarantee it will be called in the same Synchronization Context (assuming one exists in the original call).
public void SomeAsycMethod ( Action<object> onCompleteCallBack )
{
// get the current context
var context = SynchronizationContext.Current;
Task.Factory.StartNew( () =>
{
Thread.Sleep( 1000 );// do some work;
// lastly call the onCompleteCallBack on 'ThisThread'
onCompleteCallBack( "some result" );
// I am looking for something like:
context.Post(s => onCompleteCallBack ("some result"), null);
});
}
For example, in a Windows Forms or WPF program, the above will make sure that the callback is called on the GUI thread (via the message loop or dispatcher, accordingly). Similarly for ASP.NET context.
Having said that, I agree with Justin Harvey in that returning a Task<T> will probably be a better design.
Actually if you're using Task-based asynchronous programming I suggested you refactor your code to return Task<T> and give an ability to your client itself to decide in what context to call callback method (and facilitate future migration to C# 5.0 ;):
public Task<string> SomeMethodAsync()
{
return Task.Factory.StartNew(() => "some result");
}
If you definitely know that you're going to call this method from UI thread you can use following:
var task = SomeMethodAsync();
task.ContinueWith(t => textBox.Text = t.Result, TaskScheduler.FromSynchronizationContext);
This approach is better because it provide more clear separation of concern and give an ability to use your asynchronous method in any context without any dependencies to synchronization context. Some client can call this method from UI thread (and in this case TaskScheduler.FromSynchronizationContext would behave as expected - your "continuation" would be called in UI thread), some of them could use your method from non-UI thread as well without such requirements like processing results in the same thread that initiate asynchronous operation.
Task<T> is a perfect class that represents asynchronous operation as a first class object that helps not only obtain only more declarative code but more clear, easy to read and easy to test (you can easily mock this method and return "fake" task object).
Related
When I want to make a method to be accessible synchronously and asynchronously and then I wrap it inside of a Thread and return the result via a delegate callback.
Is this is a good strategy or is it a really bad way of programming?
public delegate void FooDelegate(bool foo);
public bool FooMethod()
{
//snychron operation
return true;
}
public void FooMethodAsync(FooDelegate fooDelegate)
{
ThreadStart fooThreadStart = () =>
{
fooDelegate?.Invoke(FooMethod());
};
Thread fooThreadStartThread = new Thread(fooThreadStart) { IsBackground = true };
fooThreadStartThread.Start();
}
call the methods:
FooClass fooClass = new FooClass();
//Call Synchron
var fooResult = fooClass.Disconnect();
//Call with Callback async
fooClass.DisconnectAsync(ResultCallback);
private static void ResultCallback(bool foo)
{
}
Edit
Here is a good reading:
https://learn.microsoft.com/en-us/dotnet/csharp/async (thanks pstrjds)
https://www.microsoft.com/en-us/download/details.aspx?id=19957 (Task-based Asynchronous Pattern)
No, that's not a good pattern. You should only expose both synchronous and asynchronous methods for an operation when the asynchronous implementation is inherently asynchronous in nature (and the synchronous implementation is inherently synchronous in nature), rather than simply a call to the synchronous implementation in a new thread, or a thread pool thread. (An exception can sometimes be made for situations where an object needs to implement an interface providing a synchronous and asynchronous implementation, even if only one makes sense.) If the caller wants to perform the synchronous operation asynchronously in a new thread, or a thread pool thread, they can easily do so themselves, in the situations where it's necessary. This also more effectively communicates what's going on. If a caller sees an asynchronous method they're going to assume that that operation is inherently asynchronous, which would be a false assumption in your case.
Additionally, it's not considered a good practice anymore to use a callback based model. Instead, the Task based model is used, in which an asynchronous method returns a Task, which can itself be used to add a continuation to be run when the asynchronous operation finishes, along with providing numerous other features.
public void FooMethodAsync(FooDelegate fooDelegate)
{
Task.Run(() => {
var result = FooMethod();
fooDelegate(result);
});
}
This method is unstable for exceptions. Task.Run will end immediately but if exceptions will be raised inside FooMethod or fooDelegate, your application will be aborted. It's no so good but you can ignore these exceptions:
public void FooMethodAsync(FooDelegate fooDelegate)
{
Task.Run(() => {
try
{
var result = FooMethod();
fooDelegate(result);
}
catch
{
// Who cares?
}
});
}
No, this is not the way. You should use the Task and Task<T> classes as return type, and use Task.Run() in your method to invoke operations in thread pool threads, this is called "Task-based Asynchronous Pattern".
internal Task<Bitmap> RenderAsync(
ImageData data, CancellationToken cancellationToken)
{
return Task.Run(() =>
{
var bmp = new Bitmap(data.Width, data.Height);
for(int y=0; y<data.Height; y++)
{
cancellationToken.ThrowIfCancellationRequested();
for(int x=0; x<data.Width; x++)
{
// render pixel [x,y] into bmp
}
}
return bmp;
}, cancellationToken);
}
Also, your method must have the async keyword in order to be called from async code.
More here:
https://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx
I have an abstract class whose method is define as like this
public abstract class FooBase : IDisposable
{
protected abstract bool GetData(params object[] getDataParams);
}
I am using this abstract class like this and trying to run the GetData method asynchronously
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(() =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
What I am trying to find out is: Am I doing it right or wrong, or if there is any other better way to achieve the same goal.
Update
If i change my method like this would it be called asynchronously or not
public class SomeClass : FooBase
{
protected override bool GetData(params object[] getDataParams)
{
var task = Task.Factory.StartNew(async () =>
{
using (var adapter = new DataAdapter())
{
// Take your time and fetch the data
}
});
task.Wait();
return true;
}
}
Appreciate your comments on this.
There is no way to run a synchronous method other than synchronously.
You can wrap the result in something that looks like it was run asynchronously (eg. Task.FromResult), or run in another thread.1 But the synchronous method will still block the thread it is running on.
(The reverse, blocking on an asynchronous operation, is trivial. This is why you need to have the underlying operations asynchronous because you can build both synchronous and asynchronous methods on top.)
Update (for update in question):
That additional code – specifically the task.Wait() statement – will cause the caller's thread to block while waiting for the task to complete. That task will run on another thread causing that thread to block. Ie. you are causing two threads (caller, and a thread pool thread) to block. If the underlying method was called directly only the caller's thread would be blocked.
You have two approaches:
Best: use ADO.NET's asynchronous operations. (This means not using DataTables/DataAdaptor but IMHO that's a good move anyway: all they do is move operations that should be done on the database into the client.)
Offload to another thread, but return a Task<TResult> to the caller, only marking the Task as complete then the underlying operation is complete. Something like:
protected override Task<bool> GetData(params object[] getDataParams) {
var tcs = new TaskCompletionSource<bool>();
Task.Factory.StartNew(async () => {
using (var adapter = new DataAdapter()) {
// Take your time and fetch the data
tcs.SetResult(the-result);
}
});
return tcs.Task;
}
Note here the return from GetData is a Task<bool>: the caller needs to either wait or do something else concurrently and then get the result of the data operation. If the caller just waits then you have two blocked threads. (C# 5's await is different: the caller also becomes asynchronous.)
1 For the avoidance of doubt: this can be made to look like a normal, Task<T> returning, asynchronous method (eg. making use of TaskCompletionSource<T> off loading the blocking from the current thread to some thread in the thread pool). But it is still a blocking operation: just blocking a different thread.
I have a constructor that call Task.Run() like this:
public MyPage() {
Task.Run(() => {
MyHeavyCpuMethod();
});
}
Here, MyPage() is the constructor of a UI component, and I don't want MyHeavyCpuMethod() to run on my UI thread, so I offload it with Task.Run() in a fire-and-forget fashion since I don't really care when MyHeavyCpuMethod() finishes.
However, this way if MyHeavyCpuMethod() throws, I can't handle the exception that is in the returned Task.
How can I do error handling in this case?
One option is to use async/await... which doesn't work with a constructor, but which can work in a static method:
public static async Task<MyPage> CreateInstance()
{
await Task.Run(...);
// Anything else asynchronous you want to use
return new MyPage();
}
And then assuming you're using this from an async method, you can just use:
MyPage page = await MyPage.CreateInstance();
That way, if the CPU-bound task fails, you won't even get to the constructor call. The constructor call itself is expected to be fast here, as that will be on the UI thread (as you want it to be).
An alternative to this, you could potentially store the task returned by Task.Run as a field in the page, and then await that post-construction... using the normal async exception handling approaches.
Add a ContinueWith that only fires when the Task doesn't run to completion (throws an exception):
Task.Run(() => MyHeavyCpuMethod())
.ContinueWith(task => { /* some action */ }, TaskContinuationOptions.OnlyOnFaulted);
Your second task will not be run on the UI thread either, per the documentation:
Creates a continuation that executes asynchronously when the target Task completes.
You can play with a dummy method to try it out:
Task.Run(() =>
{
throw new Exception();
}).ContinueWith(t =>
{
Invoke((MethodInvoker)(() => MessageBox.Show("ERROR")));
}, TaskContinuationOptions.OnlyOnFaulted);
I am looking for a simple way to do a task in background, then update something (on the main thread) when it completes. It's in a low level 'model' class so I can't call InvokeOnMainThread as I don't have an NSObject around. I have this method:
public void GetItemsAsync(Action<Item[]> handleResult)
{
Item[] items=null;
Task task=Task.Factory.StartNew(() =>
{
items=this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(items);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This seems to work OK, but
1) Is this the best (simplest) way?
2) I'm worried about the local variable:
Item{} items=null
What stops that disappearing when the method returns before the background thread completes?
Thanks.
I think your method slightly violates a Single Responsibility Principle, because it doing too much.
First of all I suggest to change CreateItems to return Task instead of wrapping it in the GetItemsAsync:
public Task<Item[]> CreateItems(CancellationToken token)
{
return Task.Factory.StartNew(() =>
// obtaining the data...
{});
}
CancellationToken is optional but can help you if you able to cancel this long running operation.
With this method you can remove GetItemsAsync entirely because its so simple to handle results by your client without passing this delegate:
// Somewhere in the client of your class
var task = yourClass.CreateItems(token);
task.ContinueWith(t =>
// Code of the delegate that previously
// passed to GetItemsAsync method
{}, TaskScheduler.FromCurrentSynchronizationContext());
Using this approach you'll get more clear code with only one responsibility. Task class itself is a perfect tool for representing asynchronous operation as a first class object. Using proposed technique you can easily mock you current implementation with a fake behavior for unit testing without changing your clients code.
Something like this:
public void GetItemsAsync(Action<Item[]> handleResult)
{
int Id = 11;
Task<Item[]> task = Task.Factory.StartNew(() => CreateItems(Id)); // May take a second or two
task.ContinueWith(t => handleResult(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
}
Your code looks fine.
It's a perfect example of when to use async / await if you can use C# 5, but if not, you have to write it as you have done with continuations.
The items variable is captured in your lambdas, so that's fine too.
When you write a lambda that uses an outside variable, the C# compiler creates a class that contains the variable. This is called a closure and means you can access the variable inside your lambda.
Here is a nicer soultion:
public void GetItemsAsync(Action<Item[]> handleResult)
{
var task = Task.Factory.StartNew<Item[]>(() =>
{
return this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
I am new to asynchronous programming. I have a C# dll with an asynchronous method that gets called, takes a function pointer (delegate) and calls this callback function after "result" is calculated.
public delegate void CreatedDelegate(Foo result);
public void CreateAsync(CreatedDelegate createdCallback)
{
Task t = Task.Factory.StartNew(() =>
{
Foo result = ...
createdCallback(result);
});
}
The delegate callback of type "CreatedDelegate" is (in my case) a function pointer to a C++/CLI method that works with the result.
void CreatedCallback(Foo^ result)
{
// do something with result
}
So this asynchronous concept seems to work quite well in most cases, but sometimes I encounter some errors. How can I achieve it if the function "CreateAsync" is called multiple times with different computation effort, that the resulting calls to "CreatedCallback" just happen in the same order as originally "CreateAsync" was called? To make it clearer: The first call to "CreateAsync" should result in the first call to "CreatedCallback" even if a succeeding call of "CreateAsync" is faster and would actually call the callback earlier.
Maybe this can be done by allowing only one active new thread in the asynchronous "CreateAsync" at a time?
To process the callbacks in order, you'll need to implement some queueing of work items. The easiest way is probably to use BlockingCollection type (see MSDN documentation).
Instead of calling the callback, your CreateAsync method would add the task (together with the callback) to the queue:
// Queue to keep tasks and their callbacks
private BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>
queue = new BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>()
public void CreateAsync(CreatedDelegate createdCallback) {
Task<Foo> t = Task.Factory.StartNew(() => {
Foo result = ...
return result; });
queue.Add(Tuple.Create(t, createdCallback));
// ..
}
This will only add tasks and callbacks to the queue - to actually call the callback, you'll need another task that waits for the tasks in the queue (in the order in which they were added) and calls the callback:
Task.Factory.StartNew(() => {
while(true) { // while you keep calling 'CreateAsync'
// Get next task (in order) and its callback
Tuple<Task<Foo>, CreatedDelegate> op = queue.Take();
// Wait for the result and give it to callback
op.Item2(op.Item1.Result);
}
}
If order is important, then using Threads might be better:
thread queue = empty
for each task
{
if there are no free 'cpu'
wait on first thread in queue
remove thread from queue
call delegate
create thread
add thread to queue
}
while queue has threads
wait on first thread in queue
remove thread from queue
call delegate