Bja*_*ert 10 .net c# .net-4.0 task-parallel-library
我不知道我是否以错误的方式思考TPL,但我很难理解如何获得以下内容:
我有两个功能
Task<A> getA() { ... }
Task<B> getB(A a) { ... }
Run Code Online (Sandbox Code Playgroud)
这似乎经常发生:我可以异步获得A.并且给定A,我可以异步获得B.
我无法弄清楚在TPL中将这些功能链接在一起的正确方法.
这是一次尝试:
Task<B> Combined()
{
Task<A> ta = getA();
Task<Task<B>> ttb = ta.ContinueWith(a => getB(a.Result));
return ttb.ContinueWith(x => x.Result.Result);
}
Run Code Online (Sandbox Code Playgroud)
这ContinueWith是我感到困惑的地方.返回的类型是"双任务",Task<Task<B>>.这对我来说似乎有些不对劲.
更新2011-09-30:
巧合的是,我找到了TaskExtensions.Unwrap对a Task<Task<T>>进行操作的扩展方法Task<T>.所以在我们得到C#5.0之前,我可以在这样的情况下执行ta.ContinueWith(a => ...).UnWrap(),其中continuation本身返回一个任务.
Jon*_*eet 14
你getB 必须是一个返回的方法Task<B>而不是B吗?
问题ContinueWith是:
public Task<TNewResult> ContinueWith<TNewResult>(
Func<Task<TResult>, TNewResult> continuationFunction,
CancellationToken cancellationToken
)
Run Code Online (Sandbox Code Playgroud)
所以在你的情况下,因为getB回报Task<B>,你是在传递Func<Task<A>, Task<B>>,所以TNewResult是Task<B>.
如果您可以更改getB为仅返回B给定的a A,那将起作用...或者您可以使用:
return ta.ContinueWith(a => getB(a.Result).Result);
Run Code Online (Sandbox Code Playgroud)
然后lambda表达式将是类型,Func<Task<A>, B>因此ContinueWith将返回a Task<B>.
编辑:在C#5中你可以轻松地写:
public async Task<B> CombinedAsync()
{
A a = await getA();
B b = await getB(a);
return b;
}
Run Code Online (Sandbox Code Playgroud)
......所以这只是"只是"解决最终结果的问题.我怀疑它是这样的,但有错误处理:
public Task<B> CombinedAsync()
{
TaskCompletionSource<B> source = new TaskCompletionSource();
getA().ContinueWith(taskA => {
A a = taskA.Result;
Task<B> taskB = getB(a);
taskB.ContinueWith(t => source.SetResult(t.Result));
});
return source.Task;
}
Run Code Online (Sandbox Code Playgroud)
那有意义吗?
如果您熟悉LINQ(以及它背后的Monad概念),那么下面是一个简单的Task monad,它允许您编写Tasks.
Monad实施:
public static class TaskMonad
{
public static Task<T> ToTask<T>(this T t)
{
return new Task<T>(() => t);
}
public static Task<U> SelectMany<T, U>(this Task<T> task, Func<T, Task<U>> f)
{
return new Task<U>(() =>
{
task.Start();
var t = task.Result;
var ut = f(t);
ut.Start();
return ut.Result;
});
}
public static Task<V> SelectMany<T, U, V>(this Task<T> task, Func<T, Task<U>> f, Func<T, U, V> c)
{
return new Task<V>(() =>
{
task.Start();
var t = task.Result;
var ut = f(t);
ut.Start();
var utr = ut.Result;
return c(t, utr);
});
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
public static void Main(string[] arg)
{
var result = from a in getA()
from b in getB(a)
select b;
result.Start();
Console.Write(result.Result);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3454 次 |
| 最近记录: |