C# 性能和线程改进ASP.NETMVC

C# 性能和线程改进ASP.NETMVC,c#,asp.net-mvc,multithreading,C#,Asp.net Mvc,Multithreading,我对线程技术完全陌生,希望利用6核处理器并获得改进 我试图找到一些快速的胜利,我的小生意正在增长,我注意到在完成我的服务的几个部分时出现了一些性能问题(一些客户建议我),我猜其中一些可能是因为需要发送电子邮件和等待第三方响应,在不中断会话\服务的情况下,他们是否可以轻松地将此消息传递到另一个线程\上 当约会“完成”时,我有一个操作 这样更好吗 case DomainObjects.AppointmentState.Completed: var emailThread = new Thread(

我对线程技术完全陌生,希望利用6核处理器并获得改进

我试图找到一些快速的胜利,我的小生意正在增长,我注意到在完成我的服务的几个部分时出现了一些性能问题(一些客户建议我),我猜其中一些可能是因为需要发送电子邮件和等待第三方响应,在不中断会话\服务的情况下,他们是否可以轻松地将此消息传递到另一个线程\上

当约会“完成”时,我有一个操作

这样更好吗

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

欢迎有建设性的反馈。

老实说,我相信您上面概述的方法在投入生产之前需要大量的工作。想象一下,1000个用户点击你的网站——你现在有1000个后台任务,所有任务都试图同时发送消息。这可能会使您的系统在磁盘和网络IO方面出现瓶颈

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

我创建了一个非常简单的应用程序来演示这种方法,如下所示。其中的关键类是

  • MessageProcessor类,它维护队列并控制添加项目AddToQueue方法和发送消息ReadFromQueue的访问。类本身实现了,以确保应用程序中只存在一个实例(您不需要多个队列)。ReadFromQueue方法还实现了一个计时器(设置为2秒),用于指定生成任务以发送消息的频率
  • SingletonBase类只是用于实现Singleton模式的抽象类
  • MessageSender类用于发送消息的实际工作
  • 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;
                    }
                }
            }
        }
    
    使用系统;
    使用System.Collections.Concurrent;
    利用制度全球化;
    使用System.Reactive.Linq;
    运用系统反思;
    使用系统线程;
    使用System.Threading.Tasks;
    命名空间控制台应用程序9
    {
    内部课程计划
    {
    私有静态void Main(字符串[]args)
    {
    MessagingProcessor.Instance.ReadFromQueue();//启动消息发送任务
    var createMessages=new CreateMessagesForTest();
    createMessages.CreateTestMessages();//创建用于处理的示例测试消息
    Console.ReadLine();
    }
    }
    /// 
    ///只需每秒创建测试消息以发送
    /// 
    公共类CreateMessagesForTest
    {
    public void CreateTestMessages()
    {
    IObservable observable=可观测的时间间隔(时间跨度从秒(1));
    //取消代币
    var source=新的CancellationTokenSource();
    //创建要执行的任务。
    动作动作=(CreateMessage);
    //在任务执行时订阅可观察内容。
    可观察。订阅(x=>
    {
    var任务=新任务(操作);
    task.Start();
    },source.Token);
    }
    私有静态void CreateMessage()
    {
    var message=新邮件{EMailAddress=“aa@aa.com,MessageBody=“abcdefg”};
    MessagingProcessor.Instance.AddToQueue(消息);
    }
    }
    /// 
    ///要发送的电子邮件的内容
    /// 
    公共类消息
    {
    公共字符串电子邮件地址{get;set;}
    公共字符串MessageBody{get;set;}
    }
    /// 
    ///处理处理消息的所有方面,只允许该类的一个实例
    ///随时
    /// 
    公共类MessagingProcessor:SingletonBase
    {
    专用消息处理器()
    {
    }
    私有ConcurrentQueue_messagesQueue=新ConcurrentQueue();
    //创建一个信号量来限制在任何给定时间可以发送电子邮件的线程数
    //在这种情况下,在任何给定的时间只允许处理2
    私有静态只读信号量slim信号量=新信号量slim(2,2);
    公共无效AddToQueue(消息)
    {
    _messagesQueue.Enqueue(message);
    }
    /// 
    ///用于启动发送电子邮件的过程
    /// 
    public void ReadFromQueue()
    {
    IObservable-observable=可观测的时间间隔(TimeSpan.FromSeconds(2));
    //取消代币
    var source=新的CancellationTokenSource();
    //创建要执行的任务。
    动作动作=(发送消息);
    //在任务执行时订阅可观察内容。
    可观察。订阅(x=>
    {
    var任务=新任务(操作);
    task.Start();
    },source.Token);
    }
    /// 
    ///处理队列的解队列和同步
    /// 
    公共无效发送消息()
    {
    尝试
    {
    Semaphore.Wait();
    信息;
    while(_messagesque.TryDequeue(out message))//如果我们有消息要发送
    {
    var messageSender=new messageSender()
    
        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;
                    }
                }
            }
        }