系统会向核心发送报文,但是核心并不是可以完全可以接受我们的消息并返回。现在需要实现这样一个功能,系统设定发往核心的最大session数,如果超过了这个限制则等待,直到核心给我们的系统返回处理情况,再继续发送。 系统和核心的交互式通过中间件Tuxedo来完成的。
首先想到的是使用队列,再起一个监控线程,每隔一段时间监控一下队列,如果队列里的任务项已经发送完成且返回,则把此任务项从队列里面删除,在把未发送的正在等待的任务项发送给核心。此方案实现较复杂,放弃了。
我用池实现了这个功能。具体的方案是这样的,在发送消息之前,我会从Pool中取出一个连接(GetAppContext),如果连接已经用完,则等待其它连接的释放;发送消息完且取得返回值之后,则释放这个链接,同时通知等待的线程可以获取连接(Release)。具体的代码我贴上来:
using System.Collections.Generic;
using System.Text;
using Bea.Tuxedo.ATMI;
using System.Threading;
namespace Interface.Tuxedo
... {
public class TuxedoPool
...{
private static List<int> list = new List<int>();
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
private const Int16 MaxLength = 5;//最多同时发送5条给核心
static TuxedoPool()
...{
for (int i = 0; i < MaxLength; i++)
...{
list.Add(i);
}
}
public static AppContext GetAppContext()
...{
if (list.Count > 0)
...{
lock (list)
...{
if (list.Count > 0)
...{
list.RemoveAt(0);
TypedTPINIT typedTPINIT = new TypedTPINIT();
typedTPINIT.flags = TypedTPINIT.TPMULTICONTEXTS;
AppContext ac = AppContext.tpinit(typedTPINIT);
return ac;
}
}
Console.WriteLine("WaitOne In " + Thread.CurrentThread.Name);
resetEvent.WaitOne();
return GetAppContext();
}
else
...{
Console.WriteLine("WaitOne Out " + Thread.CurrentThread.Name);
resetEvent.WaitOne();
return GetAppContext();
}
}
public static void Release()
...{
lock (list)
...{
Console.WriteLine("Release " + list.Count.ToString() + " " + Thread.CurrentThread.Name);
list.Add(1);
resetEvent.Set();
}
}
}
}
但是经过测试,发现效率较未使用池之前有所降低,之前发100笔任务只需要几秒钟,使用池之后大概需要15S,时间增加了好几倍,且随着任务量的增多比率呈上升的趋势。经过分析,发现是因为我用了ManualResetEvent 的原因,换成AutoResetEvent后,速度明显上升。原因在于当调用了ManualResetEvent.Set()后,所有等待的线程都被触发,消耗了大量的时间;而AutoResetEvent.Set()则只触一条等待的线程。关于两者的用法,我在"AutoResetEvent与ManualResetEvent区别 "中做了详细的解释。
在实际应用中,上面的代码还有一些缺陷:一是如果在排队的任务项超时如何处理,二是发往核心的任务项如果一直没有返回,则在排队的所有任务项一直处于等待状态,系统会造成死锁的状况。基于这两点考虑,我修改了一下程序,贴上代码:
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Interface.Tuxedo
... {
/**//// <summary>
/// Tuxedo连接池
/// </summary>
public class TuxedoPool
...{
private static Dictionary<object, DateTime> list = new Dictionary<object, DateTime>();
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
private const Int16 MaxTaskCount = 5;//最多同时发送5条给核心
private const Int32 WaitMilliSecondsTimeout = 1000 * 60 * 2;//等待的任务项等待两分钟则超时返回
private const double MonitorInterval = 5000.0;//监控线程每5秒检测一次
private const double ExecutingSecondsTimeout = 10;//发送中的任务项超过10秒钟则超时
private const string EventSourceName = "TuxedoLibrary"; //系统日志事件源名称
static TuxedoPool()
...{
//启动一个监控线程
Thread monitorThread = new Thread(new ThreadStart(MonitorPool));
monitorThread.Start();
}
/**//// <summary>
/// 获取连接
/// </summary>
/// <returns>获取到连接则返回object,否则返回null</returns>
public static object GetConnection()
...{
if (list.Count < MaxTaskCount)
...{
lock (list)
...{
if (list.Count < MaxTaskCount)
...{
object obj = new object();
list.Add(obj, DateTime.Now);
return obj;
}
}
}
return WaitingSignal();
}
/**//// <summary>
/// 等待信号量
/// </summary>
/// <returns>获取到连接则返回object,否则返回null</returns>
private static object WaitingSignal()
...{
Console.WriteLine("Wait " + Thread.CurrentThread.Name);
bool bObtain = resetEvent.WaitOne(WaitMilliSecondsTimeout, false);
if (!bObtain)
return null;
return GetConnection();
}
/**//// <summary>
/// 释放连接
/// </summary>
/// <param name="obj">获取到的object</param>
public static void Release(object obj)
...{
lock (list)
...{
try
...{
list.Remove(obj);
}
catch (Exception e)
...{
LogWirter logWirter = new LogWirter(EventSourceName);
logWirter.LogEvent(Thread.CurrentThread.Name + " StatkTrace: " + e.StackTrace);
}
Console.WriteLine("Release " + list.Count.ToString() + " " + Thread.CurrentThread.Name);
}
resetEvent.Set();
}
/**//// <summary>
/// 启动一个监测线程,定时检测队列
/// </summary>
private static void MonitorPool()
...{
try
...{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = MonitorInterval;
timer.Enabled = true;
timer.AutoReset = true;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
}
catch (Exception e)
...{
LogWirter logWirter = new LogWirter(EventSourceName);
logWirter.LogEvent(e.StackTrace + " " + e.Message);
}
}
/**//// <summary>
/// 检测队列
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
...{
try
...{
lock (list)
...{
List<object> objList = new List<object>();
foreach (object obj in list.Keys)
...{
DateTime dtBegin = list[obj];
if ((DateTime.Now.Ticks - dtBegin.Ticks) / 10000000.0 >= ExecutingSecondsTimeout)
objList.Add(obj);
}
foreach (object obj in objList)
...{
list.Remove(obj);
resetEvent.Set();
}
}
}
catch (Exception ex)
...{
LogWirter logWirter = new LogWirter(EventSourceName);
logWirter.LogEvent(ex.StackTrace + " " + ex.Message);
}
}
}
}