基于网络电话的软交换客户端信息监控实现,定义了一个同步发送命令的实现:
1、当系统接收到来自软交换的信息时,如果是命令响应,则将命令响应结果放到一个单独的队列
2、以异步的方式发送命令到软交换,然后监控命令队列是否有元素,有则返回该元素,否则循环等待。
现象:
1、当我向软交换(freeswitch)发送一般命令(如event、auth、log等)时,这个过程是OK的。
2、当我向软交换(freeswitch)发送api指令(如api originate、bgapi originate等)时,能接收到命令的响应信息,但是,task.Wait 却不终止等待。
现在,也不知道问题是软交换的问题还是task的问题,表面分析,都不应该有这样的现象。
代码如下:
/// <summary> /// 执行外部命令 /// </summary> /// <param name="command"></param> /// <returns></returns> public CommandResult Command(ICommand command) { var task = SendCommandAsync(command); //发送event、log、auth等命令正常 //发送api/bgapi指令,如api originate、bgapi originate时,这个wait一直等待 task.Wait(); return new CommandResult(task.Result); } /// <summary> /// 异步命令发送 /// </summary> /// <param name="command"></param> /// <returns></returns> public async Task<ESLMessage> SendCommandAsync(ICommand command) { return await Task.Factory.StartNew(() => { string message = command.ToString(); _socket._messageProductor.SendMessage(message); while (!_disposed) { if (this._commandQueue.Count > 0) { //无论是event、log、auth命令,还是api/bgapi命令,都正常的收到了命令响应,能执行到这里 return _commandQueue.Dequeue(); } sleep(); } return null; }); }
发现新问题:
1、我的这个客户端的启动是在application_start时,启动后,把client静态式的存在于静态类中
2、调用是通过一个http请求,然后使用这个client去执行命令
3、无论是api/bgapi命令还是event、auth、log等命令,如果i在application_start(也就是client创建时)执行是没问题的,但是,通过http请求执行,则无论什么命令都有问题。
4、奇怪的是:要么不执行,要么不监听不到命令响应,为毛会使得task.Wait不终止?
问题确认:
在asp.net中(别的系统未确认),每一个http请求,只能有一个线程运行。如果在一个请求里开启多个线程或异步任务,这些线程或异步任务,必须在主线程(http请求线程)返回后才会启动运行,这个也是最终导致我这个问题的原因,或者也是大家说的,在http请求中,要么同步,要么异步吧。
asp.net没有这种限制,你说的这种情况估计为错误的使用task,导致异步方法等待上下文,而http请求的线程拿着上下文又等着task的result。
@Daniel Cai: 问题也就如你所说,在http请求中,要异步就全异步,不要异步转同步。
要异步就全异步,不要一半异步一半同步,最后很可能会死锁。
#1 ConfigureAwait(false)
#2 public async Task<CommandResult> CommandAsync(ICommand command)
...
跟这个没关系,是另外一个原因导致的,再考虑新的实验方案