zoukankan      html  css  js  c++  java
  • 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这边消息队列为什么要用多线程呢?

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

  • 相关阅读:
    Mac + Python3 安装scrapy
    Pyqt4+Eric6+python2.7.13(windows)
    js基础⑥
    python模块之os,sys
    Python模块之random
    Python模块之PIL
    js基础⑤
    js基础④
    js基础③
    centOS目录结构详细版
  • 原文地址:https://www.cnblogs.com/huaizuo/p/2517289.html
Copyright © 2011-2022 走看看