一个任务池的实现

来源:互联网 发布:詹姆斯热火时期数据 编辑:程序博客网 时间:2024/05/01 10:42

        系统会向核心发送报文,但是核心并不是可以完全可以接受我们的消息并返回。现在需要实现这样一个功能,系统设定发往核心的最大session数,如果超过了这个限制则等待,直到核心给我们的系统返回处理情况,再继续发送。 系统和核心的交互式通过中间件Tuxedo来完成的。
       首先想到的是使用队列,再起一个监控线程,每隔一段时间监控一下队列,如果队列里的任务项已经发送完成且返回,则把此任务项从队列里面删除,在把未发送的正在等待的任务项发送给核心。此方案实现较复杂,放弃了。
       我用池实现了这个功能。具体的方案是这样的,在发送消息之前,我会从Pool中取出一个连接(GetAppContext),如果连接已经用完,则等待其它连接的释放;发送消息完且取得返回值之后,则释放这个链接,同时通知等待的线程可以获取连接(Release)。具体的代码我贴上来:

 

using System;
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;
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);
            }

        }

    }

}
原创粉丝点击