petshop异步和多线程

最近异步和多线程一直困扰着我,我也将用一定的时间去慢慢的理解。突然想到petshop里面有用到异步和多线程,自己也看了,还是总结下好。

首先,要讲petshop的异步还是要从order订单策略开始讲起,先看下IBLLStrategy.IOrderStrategy这个接口:

public interface IOrderStrategy  {

        void Insert(PetShop.Model.OrderInfo order);
    }

 然后看下BLL对订单的两种实现方式,一种是异步一种是同步的,同步的就不必多说了,就直接看下异步的吧:

public class OrderAsynchronous : IOrderStrategy
    {
        // Get an instance of the MessagingFactory
        // Making this static will cache the Messaging instance after the initial load
        private static readonly PetShop.IMessaging.IOrder asynchOrder = PetShop.MessagingFactory.QueueAccess.CreateOrder();

        /// <summary>
        /// This method serializes the order object and send it to the queue for asynchronous processing
        /// </summary>
        /// <param name="order">All information about the order</param>
        public void Insert(PetShop.Model.OrderInfo order) {

            asynchOrder.Send(order);
        }
    }

 这个OrderAsynchronous的实现是通过MessagingFactory工厂类来发送order消息的,具体怎么实现这边就不细说了,由于本人的博客一般地写给自己看,所以就没有写得那么详细了。

这个订单的异步是分两步进行的:第一,吧订单插入到消息队列中,第二,做一个后台的控制程序,实时地吧消息队列的值插入到数据库中。这样的话更好的提高网站的性能。

那么,这个时候是不是要来看下这个后台的控制程序是怎么运行的呢?

static void Main() {

            Thread workTicketThread;
            Thread[] workerThreads = new Thread[threadCount];

            for (int i = 0; i < threadCount; i++) {

                workTicketThread = new Thread(new ThreadStart(ProcessOrders));

                // Make this a background thread, so it will terminate when the main thread/process is de-activated
                workTicketThread.IsBackground = true;
                workTicketThread.SetApartmentState(ApartmentState.STA);

                // Start the Work
                workTicketThread.Start();
                workerThreads[i] = workTicketThread;
            }

            Console.WriteLine("Processing started. Press Enter to stop.");
            Console.ReadLine();
            Console.WriteLine("Aborting Threads. Press wait...");

            //abort all threads
            for (int i = 0; i < workerThreads.Length; i++) {

                workerThreads[i].Abort();
            }

            Console.WriteLine();
            Console.WriteLine(totalOrdersProcessed + " Orders processed.");
            Console.WriteLine("Processing stopped. Press Enter to exit.");
            Console.ReadLine();
        }

        /// <summary>
        /// Process a batch of asynchronous orders from the queue and submit them to the database within a transaction
        /// </summary>
        private static void ProcessOrders() {

            // the transaction timeout should be long enough to handle all of orders in the batch
            TimeSpan tsTimeout = TimeSpan.FromSeconds(Convert.ToDouble(transactionTimeout * batchSize));

            Order order = new Order();
            while (true) {

                // queue timeout variables
                TimeSpan datetimeStarting = new TimeSpan(DateTime.Now.Ticks);
                double elapsedTime = 0;

                int processedItems = 0;

                ArrayList queueOrders = new ArrayList();

                //OrderInfo orderData = orderQueue.Receive(timeout);
                using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, tsTimeout)) {
                    // Receive the orders from the queue
                    for (int j = 0; j < batchSize; j++) {

                        try {
                            //only receive more queued orders if there is enough time
                            if ((elapsedTime + queueTimeout + transactionTimeout) < tsTimeout.TotalSeconds) {
                                queueOrders.Add(order.ReceiveFromQueue(queueTimeout));
                            }
                            else {
                                j = batchSize;   // exit loop
                            }

                            //update elapsed time
                            elapsedTime = new TimeSpan(DateTime.Now.Ticks).TotalSeconds - datetimeStarting.TotalSeconds;
                        }
                        catch (TimeoutException) {

                            //exit loop because no more messages are waiting
                            j = batchSize;
                        }
                    }

                    //process the queued orders
                    for (int k = 0; k < queueOrders.Count; k++) {
                        order.Insert((OrderInfo)queueOrders[k]);
                        processedItems++;
                        totalOrdersProcessed++;
                    }

                    //batch complete or MSMQ receive timed out
                    ts.Complete();
                }

                Console.WriteLine("(Thread Id " + Thread.CurrentThread.ManagedThreadId + ") batch finished, " + processedItems + " items, in " + elapsedTime.ToString() + " seconds.");
            }
        }

 首先,定义了线程数组,这里的threadcount是2,那么 就是两个线程同时在运行,提高执行效率。然后看下线程执行的函数ProcessOrders吧,他可以分为两步,第一是吧消息队列的值ArrayList,然后再从中取值,最后插入到数据库中。

这边的异步是人为的都,二并非某某的Begin** End**.

 

---212-7-25

之前对为什么这边会用多线程没有多加思考,只觉得用了多线程就是好,但是多线程该怎么样,何时用?下面贴出我今晚测试的代码:

public static void DoSomeWork()
		{
			///构造显示字符串
			string results = "";

			///创建一个Sigleton实例
            CountSigleton MyCounter = new CountSigleton().Instance();

			///循环调用四次
			for(int i=1;i<5;i++)
			{
				///开始计数
				MyCounter.Add();
                
				results +="线程";
				results += Thread.CurrentThread.Name + "——〉";
				results += "当前的计数:";
				results += MyCounter.GetCounter().ToString();
				results += "\n";
                Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread+"\n");
				Console.WriteLine(results);
				
				///清空显示字符串
				results = "";
			}
		}

为了不产生误解,我把CountSigleton类也贴出来,之前这个类是一个单例模式的,我改了。

public class CountSigleton
	{
		///存储唯一的实例
        private CountSigleton uniCounter;
   
		///存储计数值
		private int totNum = 0;  
   
		public CountSigleton() 
   
		{ 
			///线程延迟2000毫秒
			Thread.Sleep(2000);
		} 
   
	    public CountSigleton Instance() 
   
		{
            uniCounter = new CountSigleton(); 
			return uniCounter; 
   
		} 
		
		///计数加1
		public void Add()
		{ 
			totNum ++;
		}  
		
		///获得当前计数值
		public int GetCounter()
		{ 
			return totNum;
		} 

然后来看看多线程调用吧:

 Thread threadTest;
            Thread[] workerThreads = new Thread[2];
            for (int i = 0; i < 2; i++)
            {
                threadTest = new Thread(new ThreadStart(DoSomeWork));
                threadTest.Name = "thread" + i;
                threadTest.SetApartmentState(ApartmentState.STA);
                threadTest.IsBackground = true;
                workerThreads[i] = threadTest;
                threadTest.Start();
            }

这边是两个线程,直接看控制台输出的结果吧,看结果比较好说明什么:

 

这就有点像线程的两次运行,这样的结果显然不是我们想得到的。

那么这样的多线程到底有什么作用呢?好的,原归正状,petshop这边消息队列为什么要用多线程呢?

因为,这样可以跟快的事实的去取到消息队列的值。这边就是多线程的魅力所在。

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2012-05-24 23:21  小霖2012  阅读(468)  评论(0编辑  收藏  举报