gpt4 book ai didi

multithreading - 公开可取消的任务

转载 作者:行者123 更新时间:2023-12-03 13:00:54 24 4
gpt4 key购买 nike

我正在设计一个API,该API公开可取消的Task,并希望确保自己设计正确。是否存在用于公开Task的标准模式(也许类似于APM BeginXxx/EndXxx模式)?有什么建议可以改善吗?参见MyAPI.RunTest2是否演示了并行运行许多MyAPI.Run任务的最佳方法?

public static class MyAPI
{
public static Task<MyResult> Run( CancellationToken token ) {
// lazily create Task, so as to include the specified CancellationToken
return new Task<MyResult>( MyPrivateAsyncMethod, token, token );
}

private static MyResult MyPrivateAsyncMethod( object state ) {
CancellationToken ct = (CancellationToken)state;
ct.ThrowIfCancellationRequested();
return new MyResult();
}
}

public static class TestMyAPI
{
// User can start the Task directly
public static void Test1() {
CancellationTokenSource cts = new CancellationTokenSource();
MyAPI.Run( cts.Token )
.ContinueWith( task => Console.WriteLine( task.Result.ToString() ) )
.Start();
}

// User must wrap in new Tasks to get Parent/Child relationship
public static void Test2() {
CancellationTokenSource cts = new CancellationTokenSource();
Task.Factory.StartNew( () =>
{
var childTasks = new[] {
Task.Factory.StartNew<MyResult>( () => MyAPI.Run( cts.Token ).Result, cts.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default ),
Task.Factory.StartNew<MyResult>( () => MyAPI.Run( cts.Token ).Result, cts.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default )
};

Task.Factory
.ContinueWhenAll<MyResult>( childTasks, tasks => { foreach( var task in tasks ) task.ToString(); } )
.Start();
}, cts.Token );
}
}

最佳答案

我会考虑更改您的实现中的几个问题。

首先,此方法:

public static Task<MyResult> Run( CancellationToken token ) {
// lazily create Task, so as to include the specified CancellationToken
return new Task<MyResult>( MyPrivateAsyncMethod, token, token );
}

这很危险-返回 TaskTask<T>的API的约定是返回“热门”任务。这意味着您应将API设计为始终返回已在运行的任务。

这是为了防止出现问题,例如上面代码中的问题:
    MyAPI.Run( cts.Token )
.ContinueWith( task => Console.WriteLine( task.Result.ToString() ) )
.Start();

如果您看一下,可以将其重写为:
    Task<MyResult> original = MyAPI.Run( cts.Token );
Task second = original.ContinueWith( task => Console.WriteLine( task.Result.ToString() ) );
second.Start();

在这里,您实际上是在错误的任务上调用“开始”,而不是原始任务,而是继续。...一种典型的方法是使“运行”返回一个热任务,这将使您将其编写为:
    MyAPI.Run( cts.Token )
.ContinueWith( task => Console.WriteLine( task.Result.ToString() ) );

同样,在第二个示例中,它也会抬起头来。您可以 Task.Factory.StartNew,让它查看 MyAPI.Run,但是永远不要在内部的任务上实际调用 Start。因此,这些任务将永远不会开始也永远不会完成。

其次,我建议使用.NET 4.5中显示的新命名约定,以供将来校对。这是为了使返回 TaskTask<T>的例程具有带 Async后缀的名称。在这种情况下,它将是 MyAPI.RunAsync。这将使您的代码看起来像将在下一版.NET中出现的框架代码。

最后,关于您的最后一个问题:

Does Test2 demonstrate the best way to run many MyAPI.Run tasks in parallel?



实际上,如果使 Run方法返回正在运行的任务,这将变得更加简单:
public static void Test2() {
CancellationTokenSource cts = new CancellationTokenSource();
var task1 = MyAPI.RunAsync(cts.Token);
var task2 = MyAPI.RunAsync(cts.Token);

Task.Factory.ContinueWhenAll<MyResult>(
new[] { task1, task2 },
tasks => {
foreach( var task in tasks ) task.ToString();
},
cts.Token);
}

关于multithreading - 公开可取消的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8331937/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com