加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c#线程异步问题

发布时间:2020-12-15 07:56:12 所属栏目:百科 来源:网络整理
导读:我有一些代码,当被调用时调用webservice,查询数据库并从本地缓存中获取值.然后它将这三个动作的返回值组合起来以产生结果.我没有按顺序执行这些操作,而是想并行异步执行它们.这是一些虚拟/示例代码: var waitHandles = new ListWaitHandle();var wsResult =
我有一些代码,当被调用时调用webservice,查询数据库并从本地缓存中获取值.然后它将这三个动作的返回值组合起来以产生结果.我没有按顺序执行这些操作,而是想并行异步执行它们.这是一些虚拟/示例代码:
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是要发信号的最后一个等待句柄.

更新:虽然我接受了菲利普的答案,但是在安德烈的评论之后,我应该补充说这也有效:

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,cacheResult));

解决方法

不幸的是,在EndInvoke()调用返回之前,始终会发出WaitHandle信号.这意味着你不能依赖于此.

如果你不能使用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,cacheResult));

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读