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  阅读(474)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示