gpt4 book ai didi

c#线程异步问题

转载 作者:太空狗 更新时间:2023-10-29 20:29:07 26 4
gpt4 key购买 nike

我有一些代码,当被调用时调用网络服务、查询数据库并从本地缓存中获取值。然后它将这三个操作的返回值组合起来产生结果。我不想按顺序执行这些操作,而是想异步并行执行它们。这是一些虚拟/示例代码:

var waitHandles = new List<WaitHandle>();

var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(res => { wsResult = callWebService.EndInvoke(res); }, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);

string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(res => { dbResult = queryDB.EndInvoke(res); }, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);

var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(res => { cacheResult = queryLocalCache.EndInvoke(res); }, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);

WaitHandle.WaitAll(waitHandles.ToArray());
Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));

问题是最后一行抛出错误,因为执行时 dbResult 仍然为 null。一旦 queryDB.EndInvoke 被调用,WaitHandle 就会发出信号并继续执行,然后将 queryDB.EndInvoke 的结果分配给 dbResult。有没有一种简洁/优雅的方法来解决这个问题?

注意:我应该补充一点,这会影响 dbResult,因为 queryDB 是最后一个发出信号的等待句柄。

更新:虽然我接受了 Philip 的回答,但在 Andrey 的评论之后,我应该补充一点,这也有效:

var waitHandles = new List<WaitHandle>();

var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(null, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);

string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(null, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);

var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(null, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);

WaitHandle.WaitAll(waitHandles.ToArray());

var wsResult = callWebService.EndInvoke(wsAsyncResult);
var dbResult = queryDB.EndInvoke(dbAsyncResult);
var cacheResult = queryLocalCache.EndInvoke(cacheAsyncResult);

Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));

最佳答案

不幸的是,WaitHandle 总是会在 EndInvoke() 调用返回之前发出信号。这意味着您不能依赖它。

如果您不能使用 4.0,则可能需要一个线程系统或手动等待句柄(或者可怕的 Sleep() hack!)。您还可以让 Invoked 方法设置结果(因此 EndInvoke 在设置结果值后 发生),但这意味着将结果移动到共享位置,而不是局部变量 - 可能需要小的重新设计。

或者 如果您可以使用 4.0,我会 - System.Threading.Tasks塞满了很棒的东西。您可以重写为:

var tasks = new List<Task>();

var wsResult = 0;
string dbResult = null;
var cacheResult = "";

tasks.Add( new Task( ()=> wsResult = CallWebService()));
tasks.Add( new Task( ()=> dbResult = QueryDB()));
tasks.Add( new Task( ()=> cacheResult = QueryLocalCache()));

tasks.ForEach( t=> t.Start());
Task.WaitAll( tasks.ToArray());

Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));

关于c#线程异步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3937035/

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