c# async update http then save to local db WhenAll ContinueWith 计时
c# async update http then save to local db WhenAll ContinueWith timing
我得到了以下代码,除了 WhenAll 上的继续之外似乎 运行 很好...等待 Task.WhenAll(syncTasks).ContinueWith ... 是 运行 在所有四种方法完成之前。对于我在这里做错的任何指导,我将不胜感激。我真的不觉得我了解如何安排复杂的异步功能以及似乎正在发生的事情支持它。这是在 Xamarin 应用程序中顺便说一句,尽管我认为这并不重要。
private async Task SyncItems()
{
var updateItemOnes = Task.Run(() =>
{
UpdateItemOnesToServer(itemOnesToUpdate).ContinueWith(async (result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
await UpdateItemOnesToLocal(itemOnesToUpdate);
}
});
});
syncTasks.Add(updateItemOnes);
var updateItemTwos = Task.Run(() =>
{
UpdateItemTwosToServer(itemTwosToUpdate).ContinueWith(async (result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
await UpdateItemTwosToLocal(itemTwosToUpdate);
}
});
});
syncTasks.Add(updateItemTwos );
//Show Loading Dialog
await Task.WhenAll(syncTasks).ContinueWith((result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
//Success
}
else
{
//Error
}
//Hide Loading Dialog
});
}
private async Task UpdateItemOnesToServer(IEnumerable<Item> itemOnesToUpdate)
{
try
{
var listofTasks = new List<Task>();
foreach (var item in itemOnesToUpdate)
{
var convertItemOneTask = Task.Run(async () => {
//Convert Image File in Item to Base64 here
});
listofTasks.Add(convertItemOneTask);
}
await Task.WhenAll(listofTasks);
var response = await _apiManager.SaveItemOnes(itemOnesToUpdate);
if (response.IsSuccessStatusCode)
{
//Update ItemOnes for Local Update with Response Values
}
}
catch
{
throw;
}
}
private async Task UpdateItemOnesToLocal(IEnumerable<Item> itemOnesToUpdate)
{
var listOfTasks = new List<Task<bool>>();
foreach (var itemOne in itemOnesToUpdate)
{
listOfTasks.Add(_localService.UpdateItemOne(itemOne));
}
await Task.WhenAll<bool>(listOfTasks);
}
private async Task UpdateItemTwosToServer(IEnumerable<ItemOne> itemTwosToUpdate)
{
try
{
var listofTasks = new List<Task>();
foreach (var item in itemTwosToUpdate)
{
var convertItemTwoTask = Task.Run(async () => {
//Convert Image File in Item to Base64 here
});
listofTasks.Add(convertItemTwoTask);
}
await Task.WhenAll(listofTasks);
var response = await _apiManager.SaveItemTwos(itemTwosToUpdate);
if (response.IsSuccessStatusCode)
{
//Update ItemTwos for Local Update with Response Values
}
}
catch
{
throw;
}
}
private async Task UpdateItemTwosToLocal(IEnumerable<ItemTwo> itemTwosToUpdate)
{
var listOfTasks = new List<Task<bool>>();
foreach (var itemTwo in itemTwosToUpdate)
{
listOfTasks.Add(_localService.UpdateItemTwo(itemTwo));
}
await Task.WhenAll<bool>(listOfTasks);
}
在此先感谢任何可以提供一些清晰信息的人。将不胜感激。
因此这段代码存在一些问题。
someTask.ContinueWith(X)
基本上这就是 "once the someTask is completed, do X"(还有更多内容,但在这种情况下可以这样想)。但是,如果您 await someTask
这将不包括 ContinueWith
部分。所以像这样 Task.WhenAll(syncTasks)
不会等待你的 ContinueWith
部分。
var updateItemOnes = Task.Run(() => UpdateItemOnesToServer())
包装器。这里没有等待,所以这将创建一个刚开始 UpdateItemOnesToServer
任务的任务。这是立即完成的。
如果您想了解实际情况,请使用此测试 class:
class TestAsyncClass
{
public async Task Run()
{
var tasks = new List<Task>();
Console.WriteLine("starting tasks");
var task1 = Task.Run(() => {
FakeServerCall1().ContinueWith(async (result) =>
{
if (!result.IsFaulted && !result.IsCanceled)
await FakeLocalCall1();
});
});
tasks.Add(task1);
var task2 = Task.Run(() => {
FakeServerCall2().ContinueWith(async (result) =>
{
if (result.IsCompletedSuccessfully)
await FakeLocalCall2();
});
});
tasks.Add(task2);
Console.WriteLine("starting tasks completed");
await Task.WhenAll(tasks);
Console.WriteLine("tasks completed");
}
public async Task<bool> FakeServerCall1()
{
Console.WriteLine("Server1 started");
await Task.Delay(3000);
Console.WriteLine("Server1 completed");
return true;
}
public async Task<bool> FakeServerCall2()
{
Console.WriteLine("Server2 started");
await Task.Delay(2000);
Console.WriteLine("Server2 completed");
return true;
}
public async Task<bool> FakeLocalCall1()
{
Console.WriteLine("Local1 started");
await Task.Delay(1500);
Console.WriteLine("Local1 completed");
return true;
}
public async Task<bool> FakeLocalCall2()
{
Console.WriteLine("Local2 started");
await Task.Delay(2000);
Console.WriteLine("Local2 completed");
return true;
}
}
你会看到输出如下:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 任务完成
- 服务器 2 完成
- Local2 已启动
- 服务器 1 完成
- Local1 已启动
- 本地2完成
- 本地1完成
注意这里 "tasks completed" 在启动两个任务后直接被调用。
现在,如果我们像这样更改 Run
方法,我认为我们将获得您正在寻找的功能:
public async Task Run()
{
var tasks = new List<Task>();
Console.WriteLine("starting tasks");
var task1 = Task.Run(async () =>
{
await FakeServerCall1();
await FakeLocalCall1();
});
tasks.Add(task1);
var task2 = Task.Run(async() =>
{
await FakeServerCall2();
await FakeLocalCall2();
});
tasks.Add(task2);
Console.WriteLine("starting tasks completed");
await Task.WhenAll(tasks);
Console.WriteLine("tasks completed");
}
将输出:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 服务器 2 完成
- Local2 已启动
- 服务器 1 完成
- Local1 已启动
- 本地2完成
- 本地1完成
- 任务完成
所以我们在这里看到 Local1 总是在 Server1 之后,Local2 总是在 Server2 之后,"tasks completed" 总是在 Local1 和 Local2
之后
希望对您有所帮助!
编辑:
从你的评论中你说你希望看到过程中发生的任何异常。这是你可以使用 ContinueWith
的地方(当抛出异常时它也会被触发:
await Task.WhenAll(tasks).ContinueWith((result) =>
{
if (result.IsFaulted)
{
foreach (var e in result.Exception.InnerExceptions)
{
Console.WriteLine(e);
}
}
});
如果更改以下测试调用:
public async Task<bool> FakeServerCall2()
{
Console.WriteLine("Server2 started");
await Task.Delay(1000);
Console.WriteLine("Crashing Server2");
throw new Exception("Oops server 2 crashed");
}
public async Task<bool> FakeLocalCall1()
{
Console.WriteLine("Local1 started");
await Task.Delay(1500);
Console.WriteLine("crashing local1");
throw new Exception("Oh ohh, local1 crashed");
}
这将是您的输出:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 服务器 2 崩溃
- 服务器 1 完成
- Local1 已启动
- 本地 1 崩溃
- System.Exception: 哦哦哦,local1 崩溃了
在 ~\TestConsoleApp\TestConsoleApp\Program.cs: 第 67 行中的 TestConsoleApp.TestAsyncClass.FakeLocalCall1()
在 TestConsoleApp.TestAsyncClass.b__0_0() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 17
- System.Exception:糟糕,服务器 2 崩溃了
在 TestConsoleApp.TestAsyncClass.FakeServerCall2() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 59
在 TestConsoleApp.TestAsyncClass.b__0_1() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 23
- 任务完成
我得到了以下代码,除了 WhenAll 上的继续之外似乎 运行 很好...等待 Task.WhenAll(syncTasks).ContinueWith ... 是 运行 在所有四种方法完成之前。对于我在这里做错的任何指导,我将不胜感激。我真的不觉得我了解如何安排复杂的异步功能以及似乎正在发生的事情支持它。这是在 Xamarin 应用程序中顺便说一句,尽管我认为这并不重要。
private async Task SyncItems()
{
var updateItemOnes = Task.Run(() =>
{
UpdateItemOnesToServer(itemOnesToUpdate).ContinueWith(async (result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
await UpdateItemOnesToLocal(itemOnesToUpdate);
}
});
});
syncTasks.Add(updateItemOnes);
var updateItemTwos = Task.Run(() =>
{
UpdateItemTwosToServer(itemTwosToUpdate).ContinueWith(async (result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
await UpdateItemTwosToLocal(itemTwosToUpdate);
}
});
});
syncTasks.Add(updateItemTwos );
//Show Loading Dialog
await Task.WhenAll(syncTasks).ContinueWith((result) => {
if (!result.IsFaulted && !result.IsCanceled)
{
//Success
}
else
{
//Error
}
//Hide Loading Dialog
});
}
private async Task UpdateItemOnesToServer(IEnumerable<Item> itemOnesToUpdate)
{
try
{
var listofTasks = new List<Task>();
foreach (var item in itemOnesToUpdate)
{
var convertItemOneTask = Task.Run(async () => {
//Convert Image File in Item to Base64 here
});
listofTasks.Add(convertItemOneTask);
}
await Task.WhenAll(listofTasks);
var response = await _apiManager.SaveItemOnes(itemOnesToUpdate);
if (response.IsSuccessStatusCode)
{
//Update ItemOnes for Local Update with Response Values
}
}
catch
{
throw;
}
}
private async Task UpdateItemOnesToLocal(IEnumerable<Item> itemOnesToUpdate)
{
var listOfTasks = new List<Task<bool>>();
foreach (var itemOne in itemOnesToUpdate)
{
listOfTasks.Add(_localService.UpdateItemOne(itemOne));
}
await Task.WhenAll<bool>(listOfTasks);
}
private async Task UpdateItemTwosToServer(IEnumerable<ItemOne> itemTwosToUpdate)
{
try
{
var listofTasks = new List<Task>();
foreach (var item in itemTwosToUpdate)
{
var convertItemTwoTask = Task.Run(async () => {
//Convert Image File in Item to Base64 here
});
listofTasks.Add(convertItemTwoTask);
}
await Task.WhenAll(listofTasks);
var response = await _apiManager.SaveItemTwos(itemTwosToUpdate);
if (response.IsSuccessStatusCode)
{
//Update ItemTwos for Local Update with Response Values
}
}
catch
{
throw;
}
}
private async Task UpdateItemTwosToLocal(IEnumerable<ItemTwo> itemTwosToUpdate)
{
var listOfTasks = new List<Task<bool>>();
foreach (var itemTwo in itemTwosToUpdate)
{
listOfTasks.Add(_localService.UpdateItemTwo(itemTwo));
}
await Task.WhenAll<bool>(listOfTasks);
}
在此先感谢任何可以提供一些清晰信息的人。将不胜感激。
因此这段代码存在一些问题。
someTask.ContinueWith(X)
基本上这就是 "once the someTask is completed, do X"(还有更多内容,但在这种情况下可以这样想)。但是,如果您 awaitsomeTask
这将不包括ContinueWith
部分。所以像这样Task.WhenAll(syncTasks)
不会等待你的ContinueWith
部分。var updateItemOnes = Task.Run(() => UpdateItemOnesToServer())
包装器。这里没有等待,所以这将创建一个刚开始UpdateItemOnesToServer
任务的任务。这是立即完成的。
如果您想了解实际情况,请使用此测试 class:
class TestAsyncClass
{
public async Task Run()
{
var tasks = new List<Task>();
Console.WriteLine("starting tasks");
var task1 = Task.Run(() => {
FakeServerCall1().ContinueWith(async (result) =>
{
if (!result.IsFaulted && !result.IsCanceled)
await FakeLocalCall1();
});
});
tasks.Add(task1);
var task2 = Task.Run(() => {
FakeServerCall2().ContinueWith(async (result) =>
{
if (result.IsCompletedSuccessfully)
await FakeLocalCall2();
});
});
tasks.Add(task2);
Console.WriteLine("starting tasks completed");
await Task.WhenAll(tasks);
Console.WriteLine("tasks completed");
}
public async Task<bool> FakeServerCall1()
{
Console.WriteLine("Server1 started");
await Task.Delay(3000);
Console.WriteLine("Server1 completed");
return true;
}
public async Task<bool> FakeServerCall2()
{
Console.WriteLine("Server2 started");
await Task.Delay(2000);
Console.WriteLine("Server2 completed");
return true;
}
public async Task<bool> FakeLocalCall1()
{
Console.WriteLine("Local1 started");
await Task.Delay(1500);
Console.WriteLine("Local1 completed");
return true;
}
public async Task<bool> FakeLocalCall2()
{
Console.WriteLine("Local2 started");
await Task.Delay(2000);
Console.WriteLine("Local2 completed");
return true;
}
}
你会看到输出如下:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 任务完成
- 服务器 2 完成
- Local2 已启动
- 服务器 1 完成
- Local1 已启动
- 本地2完成
- 本地1完成
注意这里 "tasks completed" 在启动两个任务后直接被调用。
现在,如果我们像这样更改 Run
方法,我认为我们将获得您正在寻找的功能:
public async Task Run()
{
var tasks = new List<Task>();
Console.WriteLine("starting tasks");
var task1 = Task.Run(async () =>
{
await FakeServerCall1();
await FakeLocalCall1();
});
tasks.Add(task1);
var task2 = Task.Run(async() =>
{
await FakeServerCall2();
await FakeLocalCall2();
});
tasks.Add(task2);
Console.WriteLine("starting tasks completed");
await Task.WhenAll(tasks);
Console.WriteLine("tasks completed");
}
将输出:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 服务器 2 完成
- Local2 已启动
- 服务器 1 完成
- Local1 已启动
- 本地2完成
- 本地1完成
- 任务完成
所以我们在这里看到 Local1 总是在 Server1 之后,Local2 总是在 Server2 之后,"tasks completed" 总是在 Local1 和 Local2
之后希望对您有所帮助!
编辑:
从你的评论中你说你希望看到过程中发生的任何异常。这是你可以使用 ContinueWith
的地方(当抛出异常时它也会被触发:
await Task.WhenAll(tasks).ContinueWith((result) =>
{
if (result.IsFaulted)
{
foreach (var e in result.Exception.InnerExceptions)
{
Console.WriteLine(e);
}
}
});
如果更改以下测试调用:
public async Task<bool> FakeServerCall2()
{
Console.WriteLine("Server2 started");
await Task.Delay(1000);
Console.WriteLine("Crashing Server2");
throw new Exception("Oops server 2 crashed");
}
public async Task<bool> FakeLocalCall1()
{
Console.WriteLine("Local1 started");
await Task.Delay(1500);
Console.WriteLine("crashing local1");
throw new Exception("Oh ohh, local1 crashed");
}
这将是您的输出:
- 开始任务
- 开始任务完成
- Server1 已启动
- Server2 已启动
- 服务器 2 崩溃
- 服务器 1 完成
- Local1 已启动
- 本地 1 崩溃
- System.Exception: 哦哦哦,local1 崩溃了 在 ~\TestConsoleApp\TestConsoleApp\Program.cs: 第 67 行中的 TestConsoleApp.TestAsyncClass.FakeLocalCall1() 在 TestConsoleApp.TestAsyncClass.b__0_0() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 17
- System.Exception:糟糕,服务器 2 崩溃了 在 TestConsoleApp.TestAsyncClass.FakeServerCall2() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 59 在 TestConsoleApp.TestAsyncClass.b__0_1() 在 ~\TestConsoleApp\TestConsoleApp\Program.cs:line 23
- 任务完成