Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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# 最佳异步while方法_C#_.net_Multithreading_Async Await - Fatal编程技术网

C# 最佳异步while方法

C# 最佳异步while方法,c#,.net,multithreading,async-await,C#,.net,Multithreading,Async Await,我需要编写一些异步代码,这些代码本质上是试图反复与数据库对话并初始化数据库。通常第一次尝试会失败,因此需要重试 在过去的日子里,我会使用类似的模式: void WaitForItToWork() { bool succeeded = false; while (!succeeded) { // do work succeeded = outcome; // if it worked, mark as succeeded, else retr

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

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

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
中实现此模式

更新


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

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

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;
}
你可以简单地做到这一点:

private async void Form1_Load(object sender, EventArgs e)
{
    bool result = await WaitForItToWork();
    MessageBox.Show("WaitForItToWork done:" + result.toString()); // true or false
}
然而,这也会使
Form1\u Load
成为一种异步方法

[更新]

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

// 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());
}
//用于测试的假结果()方法
bool output(){return new Random().Next(0,99)>50;}
//使用异步/等待
异步任务WaitForItToWorkAsync()
{
var=false;
而(!成功)
{
succeed=output();//如果成功,则将其设为成功,否则重试
等待任务。延迟(1000);
}
返回成功;
}
//没有异步/等待
任务WaitForItToWorkAsyncTap()
{
var context=TaskScheduler.FromCurrentSynchronizationContext();
var tcs=new TaskCompletionSource();
var=false;
动作闭包=null;
闭包=委托
{
succeed=output();//如果成功,则将其设为成功,否则重试
任务。延迟(1000)。与(代表)继续
{
如果(成功)
tcs.SetResult(成功);
其他的
闭包();
},上下文);
};
//同步启动任务逻辑
//它也可以同步结束!(例如,如果我们使用“Task.Delay(0)”)
闭包();
返回tcs.Task;
}
//启动两个任务并异步处理每个任务的完成
私有void StartWaitForItToWork()
{
WaitForItToWorkAsync().ContinueWith((t)=>
{
Show(“WaitForItToWorkAsync complete:+t.Result.ToString());
},TaskScheduler.FromCurrentSynchronizationContext());
WaitForItToWorkAsyncTap().ContinueWith((t)=>
{
Show(“WaitForItToWorkAsyncTap complete:+t.Result.ToString());
},TaskScheduler.FromCurrentSynchronizationContext());
}
//等待每个任务(StartWaitForItToWorkAsync本身是异步的)
专用异步任务StartWaitForItToWorkAsync()
{
bool result=wait WaitForItToWorkAsync();
Show(“WaitForItToWorkAsync complete:+result.ToString());
结果=等待WaitForItToWorkAsyncTap();
Show(“WaitForItToWorkAsyncTap complete:+result.ToString());
}

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

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

    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
            }
        });
    }

请参阅。

您实际上不需要
waitforwork
方法,只需等待数据库初始化任务:

async Task Run()
{
    await InitializeDatabase();
    // Do what you need after database is initialized
}

async Task InitializeDatabase()
{
    // Perform database initialization here
}
如果有多段代码调用
WaitForItToWork
,则需要将数据库初始化包装到
任务中,并在所有工作程序中等待它,例如:

readonly Task _initializeDatabaseTask = InitializeDatabase();

async Task Worker1()
{
    await _initializeDatabaseTask;
    // Do what you need after database is initialized
}

async Task Worker2()
{
    await _initializeDatabaseTask;
    // Do what you need after database is initialized
}

static async Task InitializeDatabase()
{
    // Initialize your database here
}

只需提供另一个解决方案

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);
            }
        });
    }
公共静态void WaitForCondition(Func predict)
{
Task.Delay(TimeSpan.From毫秒(1000)).ContinueWith(=>
{
var结果=预测();
//条件结果为false,我们需要再次等待。
如果(结果==false)
{
等待条件(预测);
}
});
}

我会简单地通过执行
this.WaitForItToWork()来调用它吗-异步库会为我处理线程吗?你会像等待这个一样调用它。WaitForItToWork()
,整个调用链必须重构才能支持这个。。。我将详细说明我的答案,包括更多信息。@Chris:你必须记住使用“等待”关键字。经验法则:始终“等待”必须与“异步”函数耦合。所以,你应该做一些事情,比如等待WaitForItToWork();我不想等待它,我想产生这个任务,并继续我所做的我刚刚更新了我的答案,希望它现在更有意义。实际上,您不需要等待(没有什么比阻塞
睡眠
)。
wait Task.Delay()
的最佳类比可能是计时器事件
async/await
只是编译器提供的一种语法糖。在某种程度上,它类似于
node.js
,如果您熟悉它的话(尽管node的javascript缺乏语法上的便利性——一切都是通过闭包完成的——在C#中进行委托)。这正是我在回答时想要避免的。也许,我自己遗漏了一件事:://当一个aw
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);
            }
        });
    }