c# - 为 Func 切换 new Task(()=>{ })
问题描述
在回答我的其他一个问题时,有人告诉我,使用 ofnew Task(() => { })
不是一个正常的用例。我被建议Func<Task>
改用。我试图使这项工作,但我似乎无法弄清楚。(我没有在评论中拖出它,而是在这里提出一个单独的问题。)
我的具体情况是我需要任务在声明时不能正确启动,并且以后能够等待它。
这是一个使用new Task(() => { })
. 注意:这非常有效! (除了它使用new Task
.)
static async void Main(string[] args)
{
// Line that I need to swap to a Func<Task> somehow.
// note that this is "cold" not started task
Task startupDone = new Task(() => { });
var runTask = DoStuff(() =>
{
//+++ This is where we want to task to "start"
startupDone.Start();
});
//+++ Here we wait for the task to possibly start and finish. Or timeout.
// Note that this times out at 1000ms even if "blocking = 10000" below.
var didStartup = startupDone.Wait(1000);
Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");
await runTask;
Console.Read();
}
public static async Task DoStuff(Action action)
{
// Swap to 1000 to simulate starting up blocking
var blocking = 1; //1000;
await Task.Delay(500 + blocking);
action();
// Do the rest of the stuff...
await Task.Delay(1000);
}
我尝试将第二行替换为:
Func<Task> startupDone = new Func<Task>(async () => { });
但随后评论下方的行+++
无法正常工作。
我startupDone.Start()
用startupDone.Invoke()
.
但startupDone.Wait
需要任务。仅在 lambda 中返回。我不确定如何访问 lambda 之外的任务,所以我可以Wait
做到。
如何在我的代码的一部分中使用Func<Task>
并启动它并在我的代码Wait
的另一部分中为它做 a? (就像我可以用new Task(() => { })
)。
解决方案
您发布的代码无法重构以使用 aFunc<Task>
而不是冷任务,因为await
任务所需的方法(Main
方法)与控制任务的创建/启动的方法不同(的 lambda 参数DoStuff
方法)。在这种情况下,这可以使Task
构造函数的使用合法,这取决于将任务的开始委托给 lambda 的设计决定是否合理。在这个特定的例子中,startupDone
它被用作一个同步原语,表示一个条件已经满足并且程序可以继续。这可以通过使用专门的同步原语同样好地实现,例如SemaphoreSlim
:
static async Task Main(string[] args)
{
var startupSemaphore = new SemaphoreSlim(0);
Task runTask = RunAsync(startupSemaphore);
bool startupFinished = await startupSemaphore.WaitAsync(1000);
Console.WriteLine(startupFinished ? "Startup Finished" : "Startup Timed Out");
await runTask;
}
public static async Task RunAsync(SemaphoreSlim startupSemaphore)
{
await Task.Delay(500);
startupSemaphore.Release(); // Signal that the startup is done
await Task.Delay(1000);
}
在我看来SemaphoreSlim
,在这种情况下使用 a 更有意义,并使代码的意图更清晰。它还允许await
通过 timeout 异步发送信号WaitAsync(Int32)
,这不是您从Task
开箱即用中获得的东西(尽管它是可行的)。
在某些情况下,使用冷任务可能很诱人,但是当您在一两个月后重新访问您的代码时,您会发现自己感到困惑,因为必须处理可能或尚未开始的任务是多么罕见和意外.
推荐阅读
- c# - :'无法连接到任何指定的 MySQL 主机。' 错误
- oracle - PLS-00103:在预期以下情况之一时遇到符号“PROCEDURE”:
- php - 简化如何调用 PHP 函数
- java - 获取 JVMVRFY012 堆栈形状不一致;类=com/sun/xml/messaging/saaj/soap/SOAPDocumentImpl
- git - 在 Azure DevOps 中重用标签
- c# - C# EF Core QueryableExtensions.FirstOrDefaultAsync 奇怪的行为
- java - 如何获得与 sparkWebUi 相同的真实流程
- php - PHP 错误:在 Codeigniter 中只能通过引用传递变量
- database - 一个额外的列,用于解释同一行中的值何时更新
- python - 如何在 webdriver selenium google chrome 中找到没有 id、name 和 xpath 的元素