首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >最佳异步while方法

最佳异步while方法
EN

Stack Overflow用户
提问于 2013-09-03 16:37:14
回答 4查看 33.1K关注 0票数 24

我需要编写一些异步代码,这些代码本质上是试图重复地与数据库对话并初始化数据库。通常第一次尝试都会失败,因此需要重试。

在过去的日子里,我会使用类似于:

代码语言:javascript
复制
void WaitForItToWork()
{
    bool succeeded = false;
    while (!succeeded)
    {
        // do work
        succeeded = outcome; // if it worked, mark as succeeded, else retry
        Threading.Thread.Sleep(1000); // arbitrary sleep
    }
}

我意识到最近在异步模式方面对.NET做了很多更改,所以我的问题是,在探索async时,这是最好的方法,是否值得?如果是,我如何在async中实现此模式

更新

为了澄清,我想异步地产生这个工作,这样产生它的方法就不必等待它完成,因为它将在服务的构造函数中产生,所以构造函数必须立即返回。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-09-03 16:46:45

您可以像这样重构该片段:

代码语言:javascript
复制
async Task<bool> WaitForItToWork()
{
    bool succeeded = false;
    while (!succeeded)
    {
        // do work
        succeeded = outcome; // if it worked, make as succeeded, else retry
        await Task.Delay(1000); // arbitrary delay
    }
    return succeeded;
}

显然,它给您带来的唯一好处是更有效地使用线程池,因为它并不总是需要整个线程来实现延迟。

根据您获取outcome的方式,使用async/await可能会有更有效的方法来完成此工作。通常,你可能有像GetOutcomeAsync()这样的东西,它会以一种自然的方式异步地调用web服务、数据库或套接字,所以你只需要使用var outcome = await GetOutcomeAsync()

重要的是要考虑到,编译器会将WaitForItToWork拆分成多个部分,而await行中的部分将异步继续。Here's可能是关于它是如何在内部完成的最好的解释。问题是,通常在代码的某个点上,您需要同步异步任务的结果。例如:

代码语言:javascript
复制
private void Form1_Load(object sender, EventArgs e)
{
    Task<bool> task = WaitForItToWork();
    task.ContinueWith(_ => {
        MessageBox.Show("WaitForItToWork done:" + task.Result.toString()); // true or false
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

您可以简单地这样做:

代码语言:javascript
复制
private async void Form1_Load(object sender, EventArgs e)
{
    bool result = await WaitForItToWork();
    MessageBox.Show("WaitForItToWork done:" + result.toString()); // true or false
}

然而,这也会使Form1_Load成为一种异步方法。

更新

下面是我试图说明 async/await 在这种情况下的实际作用。我创建了同一逻辑的两个版本,WaitForItToWorkAsync (使用async/await)和WaitForItToWorkAsyncTap (使用TAP pattern而不使用async/await)。与第二个版本不同,第一个版本相当琐碎。因此,虽然async/await在很大程度上是编译器的语法糖,但它使异步代码更容易编写和理解。

代码语言:javascript
复制
// fake outcome() method for testing
bool outcome() { return new Random().Next(0, 99) > 50; }

// with async/await
async Task<bool> WaitForItToWorkAsync()
{
    var succeeded = false;
    while (!succeeded)
    {
        succeeded = outcome(); // if it worked, make as succeeded, else retry
        await Task.Delay(1000);
    }
    return succeeded;
}

// without async/await
Task<bool> WaitForItToWorkAsyncTap()
{
    var context = TaskScheduler.FromCurrentSynchronizationContext();
    var tcs = new TaskCompletionSource<bool>();
    var succeeded = false;
    Action closure = null;

    closure = delegate
    {
        succeeded = outcome(); // if it worked, make as succeeded, else retry
        Task.Delay(1000).ContinueWith(delegate
        {
            if (succeeded)
                tcs.SetResult(succeeded);
            else
                closure();
        }, context);
    };

    // start the task logic synchronously
    // it could end synchronously too! (e.g, if we used 'Task.Delay(0)')
    closure();

    return tcs.Task;
}

// start both tasks and handle the completion of each asynchronously
private void StartWaitForItToWork()
{
    WaitForItToWorkAsync().ContinueWith((t) =>
    {
        MessageBox.Show("WaitForItToWorkAsync complete: " + t.Result.ToString());
    }, TaskScheduler.FromCurrentSynchronizationContext());

    WaitForItToWorkAsyncTap().ContinueWith((t) =>
    {
        MessageBox.Show("WaitForItToWorkAsyncTap complete: " + t.Result.ToString());
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

// await for each tasks (StartWaitForItToWorkAsync itself is async)
private async Task StartWaitForItToWorkAsync()
{
    bool result = await WaitForItToWorkAsync();
    MessageBox.Show("WaitForItToWorkAsync complete: " + result.ToString());

    result = await WaitForItToWorkAsyncTap();
    MessageBox.Show("WaitForItToWorkAsyncTap complete: " + result.ToString());
}

关于线程化的几句话。这里没有显式创建的其他线程。在内部,Task.Delay()实现可能使用池线程(我怀疑它们使用Timer Queues,但在这个特定的示例( WinForms应用程序)中,await之后的延续将发生在相同的UI线程上。在其他执行环境中(例如控制台应用程序),它可能会在不同的线程上继续。Stephen Cleary所著的this article是理解async/await线程概念的必读书籍。

票数 36
EN

Stack Overflow用户

发布于 2013-09-03 16:51:45

如果任务是异步的,您可以尝试使用:

代码语言:javascript
复制
    async Task WaitForItToWork()
    {
        await Task.Run(() =>
        {
            bool succeeded = false;
            while (!succeeded)
            {
                // do work
                succeeded = outcome; // if it worked, make as succeeded, else retry
                System.Threading.Thread.Sleep(1000); // arbitrary sleep
            }
        });
    }

参见http://msdn.microsoft.com/en-us/library/hh195051.aspx

票数 2
EN

Stack Overflow用户

发布于 2016-05-06 16:03:11

只需提供另一种解决方案

代码语言:javascript
复制
public static void WaitForCondition(Func<bool> predict)
    {
        Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(_ =>
        {
            var result = predict();
            // the condition result is false, and we need to wait again.
            if (result == false)
            {
                WaitForCondition(predict);
            }
        });
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18587628

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档