How to conditionally run a code asynchonously using tasks

萝らか妹 提交于 2019-12-04 09:13:57

问题


I have a class in charge of retrieving resources which also caches them for quick access. The class exposes an asynchronous method for retrieving a resource:

public Task<object> GetResourceAsync(string resourceName)
{
    return Task.Factory.StartNew<object>(() =>
    {
        // look in cache

        // if not found, get from disk

        // return resource
    });
}

The client code then looks like this:

myResourceProvider.GetResourceAsync("myResource")
    .ContinueWith<object>(t => Console.WriteLine("Got resource " + t.Result.ToString()));

This way, a background thread is always used. However, I don't want the code to run asynchronously if the object was found in the cache. If it was found in the cache, I'd like to immediately return the resource and not to have to use another thread.

Thanks.


回答1:


.NET 4.5 has Task.FromResult that lets you return a Task<T>, but instead of running a delegate on a threadpool thread, it explicitly sets the task's return value.

So in the context of your code:

public Task<object> AsyncGetResource(string resourceName)
{
    object valueFromCache;
    if (_myCache.TryGetValue(resourceName, out valueFromCache)) {
        return Task.FromResult(valueFromCache);
    }
    return Task.Factory.StartNew<object>(() =>
    {
        // get from disk
        // add to cache
        // return resource
    });
}

If you're still on .NET 4.0, you can use TaskCompletionSource<T> to do the same thing:

var tcs = new TaskCompletionSource<object>();
tcs.SetResult(...item from cache...);
return tcs.Task;



回答2:


Be careful if you have UI connected thread.

In WPF it is very important, to use the Task.Run on the UI thread (eg. a button click event handler), to avoid UI problems, and running your code on a background thread.

Why? The Task.Run by default a wrapper around the Task.Factory.StartNew with the TaskScheduler.Default parameter, instead of TaskScheduler.Current.

So not enough just to call your async method like this, because this is running on the UI thread and freezing it: await SomeTaskAsync();

Instead of it you should call it inside a Task.Run:

  • Task.Run(async() => await SomeTaskAsync());

Or use your syncron method in the Task.Run:

  • Task.Run(() => SomeTask());


来源:https://stackoverflow.com/questions/8575889/how-to-conditionally-run-a-code-asynchonously-using-tasks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!