gpt4 book ai didi

Action 中的 C# 异步

转载 作者:太空狗 更新时间:2023-10-30 00:13:56 27 4
gpt4 key购买 nike

我想编写一个接受多个参数的方法,包括一个 Action 和一个重试次数并调用它。

所以我有这段代码:

public static IEnumerable<Task> RunWithRetries<T>(List<T> source, int threads, Func<T, Task<bool>> action, int retries, string method)
{
object lockObj = new object();
int index = 0;

return new Action(async () =>
{
while (true)
{
T item;
lock (lockObj)
{
if (index < source.Count)
{
item = source[index];
index++;
}
else
break;
}

int retry = retries;
while (retry > 0)
{
try
{
bool res = await action(item);
if (res)
retry = -1;
else
//sleep if not success..
Thread.Sleep(200);

}
catch (Exception e)
{
LoggerAgent.LogException(e, method);
}
finally
{
retry--;
}
}
}
}).RunParallel(threads);
}

RunParallel 是Action 的扩展方法,如下所示:

public static IEnumerable<Task> RunParallel(this Action action, int amount)
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < amount; i++)
{
Task task = Task.Factory.StartNew(action);
tasks.Add(task);
}
return tasks;
}

现在,问题是:线程正在消失或崩溃,而没有等待操作完成。

我写了这个示例代码:

private static async Task ex()
{
List<int> ints = new List<int>();
for (int i = 0; i < 1000; i++)
{
ints.Add(i);
}

var tasks = RetryComponent.RunWithRetries(ints, 100, async (num) =>
{
try
{
List<string> test = await fetchSmthFromDb();
Console.WriteLine("#" + num + " " + test[0]);
return test[0] == "test";
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}

}, 5, "test");

await Task.WhenAll(tasks);
}

fetchSmthFromDb是一个简单的任务>,它从数据库中获取一些东西,并且在这个例子之外调用时工作得很好。

每当List<string> test = await fetchSmthFromDb();行被调用,线程似乎正在关闭并且 Console.WriteLine("#" + num + " " + test[0]);甚至没有被触发,调试时也从未命中断点。

最终工作代码

private static async Task DoWithRetries(Func<Task> action, int retryCount, string method)
{
while (true)
{
try
{
await action();
break;
}
catch (Exception e)
{
LoggerAgent.LogException(e, method);
}

if (retryCount <= 0)
break;

retryCount--;
await Task.Delay(200);
};
}

public static async Task RunWithRetries<T>(List<T> source, int threads, Func<T, Task<bool>> action, int retries, string method)
{
Func<T, Task> newAction = async (item) =>
{
await DoWithRetries(async ()=>
{
await action(item);
}, retries, method);
};
await source.ParallelForEachAsync(newAction, threads);
}

最佳答案

问题出在这一行:

return new Action(async () => ...

您使用异步 lambda 启动异步操作,但不返回要等待的任务。 IE。它在工作线程上运行,但您永远不会知道它何时完成。并且您的程序在异步操作完成之前终止 - 这就是您看不到任何输出的原因。

它需要是:

return new Func<Task>(async () => ...

更新

首先,您需要拆分方法的职责,这样您就不会将重试策略(不应硬编码为检查 bool 结果)与并行运行的任务混合使用。

然后,如前所述,您运行 while (true) 循环 100 次,而不是并行执行操作。

正如@MachineLearning 指出的那样,使用 Task.Delay 而不是 Thread.Sleep

总的来说,您的解决方案如下所示:

using System.Collections.Async;

static async Task DoWithRetries(Func<Task> action, int retryCount, string method)
{
while (true)
{
try
{
await action();
break;
}
catch (Exception e)
{
LoggerAgent.LogException(e, method);
}

if (retryCount <= 0)
break;

retryCount--;
await Task.Delay(millisecondsDelay: 200);
};
}

static async Task Example()
{
List<int> ints = new List<int>();
for (int i = 0; i < 1000; i++)
ints.Add(i);

Func<int, Task> actionOnItem =
async item =>
{
await DoWithRetries(async () =>
{
List<string> test = await fetchSmthFromDb();
Console.WriteLine("#" + item + " " + test[0]);
if (test[0] != "test")
throw new InvalidOperationException("unexpected result"); // will be re-tried
},
retryCount: 5,
method: "test");
};

await ints.ParallelForEachAsync(actionOnItem, maxDegreeOfParalellism: 100);
}

您需要使用 AsyncEnumerator NuGet Package为了使用 System.Collections.Async 命名空间中的 ParallelForEachAsync 扩展方法。

关于 Action 中的 C# 异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39191791/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com