Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在不运行异步方法的情况下对其任务结果进行排队?_C#_Asynchronous_Task_Task Queue - Fatal编程技术网

C# 如何在不运行异步方法的情况下对其任务结果进行排队?

C# 如何在不运行异步方法的情况下对其任务结果进行排队?,c#,asynchronous,task,task-queue,C#,Asynchronous,Task,Task Queue,如果我有一个类,它包含一个稍后要执行的任务队列,并且我有一个async Task方法,那么我如何在不执行它的情况下将该异步方法排队 我希望“延迟”此任务,并确保调用方看到它稍后运行,就像它在方法体中等待一样。--调用方不应该知道我已将任务排入队列以供以后使用 现在,如果我的队列已满,我将在此处构造并返回一个未运行的新任务,该任务将返回我的私有异步方法的。结果: public async Task<T> ExecuteAsync<T>(T transaction) {

如果我有一个类,它包含一个稍后要执行的任务队列,并且我有一个
async Task
方法,那么我如何在不执行它的情况下将该异步方法排队

我希望“延迟”此任务,并确保调用方看到它稍后运行,就像它在方法体中等待一样。--调用方不应该知道我已将任务排入队列以供以后使用

现在,如果我的队列已满,我将在此处构造并返回一个未运行的新
任务
,该任务将返回我的私有异步方法的
。结果

public async Task<T> ExecuteAsync<T>(T transaction) {
    if (mustDelay) {
        Task<T> task = new Task<T>(t => executeAsync((T) t).Result, transaction);
        enqueue(task);
        return await task;
    }
    return await executeAsync(transaction);
}

private async Task<T> executeAsync<T>(T transaction) {
    await someWork();
    return transaction;
}
这是否确保调用方看到的同步与从方法返回等待的结果相同

如何在不运行异步方法的情况下对其任务结果进行排队

简单回答:你不能。调用
async
方法将执行该方法。它一定会开始运行。如果你想推迟通话,你需要用能做到这一点的东西来包装它

一个例子可能是
Func
,除了您设计与我们共享的一点点代码表明您希望能够返回一个承诺(
Task
),该承诺也代表了您将来将进行的调用。您可以将整个任务包装到另一个任务中,就像您的示例代码中一样,但这是一种非常繁重的方法,因为它只为了调用
async
方法而绑定(并可能创建新的)线程池线程

更好的方法(IMHO)是使用
TaskCompletionSource
。您可以在队列中存储
Func
,该队列使用返回值设置
TaskCompletionSource
,然后当您决定可以启动任务时,调用
Func

Func<Task<T>> GetFactory()
{
    return async () =>
    {
        DoRightAway();
        await DoLater();
        return DoEvenLater();
    }
}
比如:

public Task<T> ExecuteAsync<T>(T transaction) {
    if (mustDelay) {
        TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();

        enqueue(async () =>
        {
            tcs.SetValue(await executeAsync(transaction));
        });
        return tcs.Task;
    }
    return executeAsync(transaction);
}
公共任务执行同步(T事务){ 如果(必须延迟){ TaskCompletionSource tcs=新的TaskCompletionSource(); 排队(异步()=> { 设置值(等待执行同步(事务)); }); 返回tcs.Task; } 返回executeAsync(事务); } 注意,这里不需要将
ExecuteAsync()
设置为
async
。您可以返回
TaskCompletionSource
的任务,也可以返回
executeAsync()
方法返回的任务(顺便说一句,两个方法的名称仅在字母大小写上不同,这是一个可怕的想法)

还要注意,您的队列将存储
Func
对象,甚至可能存储
Action
对象(通常不支持
async void
方法,例如上面的匿名方法,但您首先没有显示任何异常处理,因此在这种情况下,您可能会发现它可以正常工作)。当您将一个项目出列时,您将调用该委托。根据您的需要,这可能是“触发并忘记”(如果您存储
操作
委托),也可能是退出队列并调用委托的方法可能会等待委托的返回值(如果您存储
Func
委托)


不幸的是,你的问题相当模糊。所以不可能提供比这更多的东西。如果您需要其他帮助,请改进问题,使其包含一个好的答案,清楚地显示您正在努力完成的任务以及您在具体理解中遇到的困难,并提供适当的解释来详细描述。

以下是一个简化的示例:

async Task<T> GetResult<T>()
{
    DoRightAway();
    await DoLater();
    return DoEvenLater();
}

Task<T> task = GetResult<T>();
//task is running or complete
我们调用此新方法来获取函数:

Func<Task<T>> function = GetFactory();
Task<T> task = function();

这可能会有所帮助:
我有一个类,它包含一个稍后要执行的任务队列,
这就是您需要解决的问题。不要那样做。@ThomasChristof,这样做充其量会造成一个问题的世界,在最坏的情况下根本不起作用;运行
async
方法会返回一个“热”任务;也就是说,任务已经启动,并且已经运行到等待未完成等待的第一个等待点。如果要将方法的操作推迟到以后,通常需要将其包装在
Func
中(也可以将
Func
包装在
Lazy
中),然后等待调用
Func
。简言之:不要混淆“我想要一个按需计算的值”单子--
Func
“我想要一个按需计算并缓存的值”monad--
Lazy--
“我想要一个将来计算的值,当它准备好时会调用我“--
任务
--monad。很明显,它们都是相似的,它们都是相互组成的,但是它们在逻辑上是不同的。您好,谢谢您的回答。我已经采纳了您的建议和@EricLippert的评论:我正在重构实现,以容纳Func,并将在TaskScheduler上包装和执行Func,而将“延迟”任务排入队列的工作将在Scheduler上进行。这样API就更有意义了(消费者将只提供一个Func,而实现将它异步,而不是从消费者那里“一直异步”)。
Task<T> task = function();
T result = await task;