性能和线程改进净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();
欢迎建设性意见
老实说,我认为您上面概述的方法在发布到生产环境之前需要做大量的工作。想象一下,如果有1000个用户点击你的网站,那么你现在有1000个后台任务试图同时发送消息。这可能会使您的系统在磁盘和网络IO方面遇到瓶颈。
虽然有许多方法可以解决这个问题,但最常见的方法之一是使用生产者-消费者队列,最好使用线程安全集合(如ConcurrentQueue)和长时间运行的活动数量,例如在任何时候通过同步机制(如SemaphoreSlim)控制的电子邮件发送正在处理的线程
我创建了一个非常简单的应用程序来演示这种方法,如下所示。其中的关键类是- MessageProcessor类,它维护队列并控制添加项目AddToQueue方法和发送消息ReadFromQueue的访问。类本身实现了Singleton模式,以确保在应用程序中只存在一个实例(您不希望有多个队列)。ReadFromQueue方法还实现了一个定时器(设置为2秒),它指定了一个任务应该多久产生一次来发送消息。
- SingletonBase类只是一个实现单例模式的抽象类 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;
}
}
}
}