我有下面的情况下,我认为可能是相当普遍:任务测序和重entracy
有一个任务(一个UI命令处理程序),它可以完成同步或异步。
命令可能比他们正在处理的速度快。
如果已经有一个命令的待处理任务,则新的命令处理程序任务应该排队并按顺序处理。
每个新任务的结果都可能取决于上一个任务的结果。
取消应该遵守,但为了简单起见,我想让它不在这个问题的范围之内。另外,线程安全(并发)不是必需的,但必须支持重入。
这里是我想要达到一个基本的例子(如一个控制台应用程序,为简单起见):
using System;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var asyncOp = new AsyncOp<int>();
Func<int, Task<int>> handleAsync = async (arg) =>
{
Console.WriteLine("this task arg: " + arg);
//await Task.Delay(arg); // make it async
return await Task.FromResult(arg); // sync
};
Console.WriteLine("Test #1...");
asyncOp.RunAsync(() => handleAsync(1000));
asyncOp.RunAsync(() => handleAsync(900));
asyncOp.RunAsync(() => handleAsync(800));
asyncOp.CurrentTask.Wait();
Console.WriteLine("\nPress any key to continue to test #2...");
Console.ReadLine();
asyncOp.RunAsync(() =>
{
asyncOp.RunAsync(() => handleAsync(200));
return handleAsync(100);
});
asyncOp.CurrentTask.Wait();
Console.WriteLine("\nPress any key to exit...");
Console.ReadLine();
}
// AsyncOp
class AsyncOp<T>
{
Task<T> _pending = Task.FromResult(default(T));
public Task<T> CurrentTask { get { return _pending; } }
public Task<T> RunAsync(Func<Task<T>> handler)
{
var pending = _pending;
Func<Task<T>> wrapper = async() =>
{
// await the prev task
var prevResult = await pending;
Console.WriteLine("\nprev task result: " + prevResult);
// start and await the handler
return await handler();
};
_pending = wrapper();
return _pending;
}
}
}
}
输出:
Test #1... prev task result: 0 this task arg: 1000 prev task result: 1000 this task arg: 900 prev task result: 900 this task arg: 800 Press any key to continue to test #2... prev task result: 800 prev task result: 800 this task arg: 200 this task arg: 100 Press any key to exit...
它可以按照要求,直到在测试2中引入再入入:
asyncOp.RunAsync(() =>
{
asyncOp.RunAsync(() => handleAsync(200));
return handleAsync(100);
});
期望的输出应该是100
,200
,而不是200
,100
,因为100
已有一个挂起的外部任务。这显然是因为内部任务同步执行,打破了外部任务的逻辑var pending = _pending; /* ... */ _pending = wrapper()
。
如何使它在测试#2中也能工作?
一个解决方案是强制每个任务的异步,Task.Factory.StartNew(..., TaskScheduler.FromCurrentSynchronizationContext()
。但是,我不想在可能在内部同步的命令处理程序强加异步执行。另外,我不想依赖任何特定同步上下文的行为(即依靠Task.Factory.StartNew
应该在创建的任务实际开始之前返回)。
在现实生活中的项目中,我对AsyncOp
位于上面负责,但无法控制命令处理程序(即无论是否在handleAsync
内)。
我已经上了很多关注你的名字很多最近好的问题和答案,有新的优质用户来到这个网站是很好的。 –