性能和线程改进净MVC

本文关键字:MVC 线程 性能 | 更新日期: 2023-09-27 18:08:50

我对线程完全不熟悉,想利用6核处理器并获得改进。

我试图找到一些快速的胜利,我的小生意正在增长,我注意到一些性能命中(几个客户建议我)当完成我的服务的几个部分时,我猜其中一些可能是需要发送电子邮件并等待第三方响应,他们是一个简单的方法来传递这个到另一个线程,而不是打破会话服务?

当约会"完成"时,我有一个动作

switch (appointment.State)
{
case DomainObjects.AppointmentState.Completed:
_clientService.SendMessageToClient(clientId,"Email title"EmailMessage(appointment, "AppointmentThankYou"), appointment.Id, userId);
break;
}

这样更好吗?

case DomainObjects.AppointmentState.Completed:
 var emailThread = new Thread(() =>  _clientService.SendMessageToClient(clientId,"Email Subject",
EmailMessage(appointment, "AppointmentThankYou"),
appointment.Id, userId))
{
IsBackground = true
};
 emailThread.Start();

欢迎建设性意见

性能和线程改进净MVC

老实说,我认为您上面概述的方法在发布到生产环境之前需要做大量的工作。想象一下,如果有1000个用户点击你的网站,那么你现在有1000个后台任务试图同时发送消息。这可能会使您的系统在磁盘和网络IO方面遇到瓶颈。

虽然有许多方法可以解决这个问题,但最常见的方法之一是使用生产者-消费者队列,最好使用线程安全集合(如ConcurrentQueue)和长时间运行的活动数量,例如在任何时候通过同步机制(如SemaphoreSlim)控制的电子邮件发送正在处理的线程

我创建了一个非常简单的应用程序来演示这种方法,如下所示。其中的关键类是
    MessageProcessor类,它维护队列并控制添加项目AddToQueue方法和发送消息ReadFromQueue的访问。类本身实现了Singleton模式,以确保在应用程序中只存在一个实例(您不希望有多个队列)。ReadFromQueue方法还实现了一个定时器(设置为2秒),它指定了一个任务应该多久产生一次来发送消息。
  1. SingletonBase类只是一个实现单例模式的抽象类
  2. MessageSender类用于发送消息的实际工作
  3. CreateMessagesForTest类简单地模拟为这个答案创建测试消息

希望有帮助

    using System;
    using System.Collections.Concurrent;
    using System.Globalization;
    using System.Reactive.Linq;
    using System.Reflection;
    using System.Threading;
    using System.Threading.Tasks;

    namespace ConsoleApplication9
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                MessagingProcessor.Instance.ReadFromQueue(); // starts the message sending tasks
                var createMessages = new CreateMessagesForTest();
                createMessages.CreateTestMessages(); // creates sample test messages for processing 
                Console.ReadLine();
            }

        }
        /// <summary>
        /// Simply creates test messages every second for sending 
        /// </summary>
        public class CreateMessagesForTest
        {
            public void CreateTestMessages()
            {
                IObservable<long> observable = Observable.Interval(TimeSpan.FromSeconds(1));
                // Token for cancelation
                var source = new CancellationTokenSource();
                // Create task to execute.
                Action action = (CreateMessage);
                // Subscribe the obserable to the task on execution.
                observable.Subscribe(x =>
                {
                    var task = new Task(action);
                    task.Start();
                }, source.Token);
            }
            private static void CreateMessage()
            {
                var message = new Message {EMailAddress = "aa@aa.com", MessageBody = "abcdefg"};
                MessagingProcessor.Instance.AddToQueue(message);
            }
        }

        /// <summary>
        /// The conents of the email to send
        /// </summary>
        public class Message
        {
            public string EMailAddress { get; set; }
            public string MessageBody { get; set; }
        }
        /// <summary>
        /// Handles all aspects of processing the messages, only one instance of this class is allowed 
        /// at any time
        /// </summary>
        public class MessagingProcessor : SingletonBase<MessagingProcessor>
        {
            private MessagingProcessor()
            {
            }

            private ConcurrentQueue<Message> _messagesQueue = new ConcurrentQueue<Message>();
            // create a semaphore to limit the number of threads which can send an email at any given time
            // In this case only allow 2 to be processed at any given time
            private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(2, 2);
            public void AddToQueue(Message message)
            {
                _messagesQueue.Enqueue(message);
            }
            /// <summary>
            /// Used to start the process for sending emails
            /// </summary>
            public void ReadFromQueue()
            {
                IObservable<long> observable = Observable.Interval(TimeSpan.FromSeconds(2));
                // Token for cancelation
                var source = new CancellationTokenSource();
                // Create task to execute.
                Action action = (SendMessages);
                // Subscribe the obserable to the task on execution.
                observable.Subscribe(x =>
                {
                    var task = new Task(action);
                    task.Start();
                }, source.Token);

            }
            /// <summary>
            /// Handles dequeing and syncronisation to the queue
            /// </summary>
            public void SendMessages()
            {
                try
                {
                    Semaphore.Wait();
                    Message message;
                    while (_messagesQueue.TryDequeue(out message)) // if we have a message to send
                    {
                        var messageSender = new MessageSender();
                        messageSender.SendMessage(message);
                    }
                }
                finally
                {
                    Semaphore.Release();
                }
            }
        }
        /// <summary>
        /// Sends the emails
        /// </summary>
        public class MessageSender
        {
            public void SendMessage(Message message)
            {
                // do some long running task
            }
        }
        /// <summary>
        /// Implements singleton pattern on all classes which derive from it
        /// </summary>
        /// <typeparam name="T">Derived class</typeparam>
        public abstract class SingletonBase<T> where T : class
        {
            public static T Instance
            {
                get { return SingletonFactory.Instance; }
            }
            /// <summary>
            /// The singleton class factory to create the singleton instance.
            /// </summary>
            private class SingletonFactory
            {
                static SingletonFactory()
                {
                }
                private SingletonFactory()
                {
                }
                internal static readonly T Instance = GetInstance();
                private static T GetInstance()
                {
                    var theType = typeof (T);
                    T inst;
                    try
                    {
                        inst = (T) theType
                            .InvokeMember(theType.Name,
                                BindingFlags.CreateInstance | BindingFlags.Instance
                                | BindingFlags.NonPublic,
                                null, null, null,
                                CultureInfo.InvariantCulture);
                    }
                    catch (MissingMethodException ex)
                    {
                        var exception = new TypeLoadException(string.Format(
                            CultureInfo.CurrentCulture,
                            "The type '{0}' must have a private constructor to " +
                            "be used in the Singleton pattern.", theType.FullName)
                            , ex);
                        //LogManager.LogException(LogManager.EventIdInternal, exception, "error in instantiating the singleton");
                        throw exception;
                    }
                    return inst;
                }
            }
        }
    }