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这边消息队列为什么要用多线程呢?
因为,这样可以跟快的事实的去取到消息队列的值。这边就是多线程的魅力所在。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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代理技术深度解析与实战指南