C# AppDomain+;命名管道序列化性能
考虑以下情况:在条形码扫描仪下扫描订单,订单号被发送到windows服务应用程序,该应用程序将计算并发回价格。除其他事项外,它还考虑了折扣券,折扣在单独的组件中处理。 我想做的是能够在运行时卸载程序集,这样就可以在不停止服务的情况下替换dll。(服务启动需要30分钟) 所以我想到了创建一个新的AppDomain的想法,它将加载程序集并在其中执行代码。通信是通过命名管道和序列化完成的。 从功能上看,它运行良好,但在生产中性能变得非常低。有人对如何使下面的代码尽可能快地运行有什么建议吗 守则解释: 对于每个具有折扣的订单,都会调用DoAction。它首先启动一个充当命名管道客户端的线程。该线程接收发送回客户端的价格。 然后加载一个新的AppDomain(如果尚未加载),并在该AppDomain的上下文中执行AppDomainCallback。在那里启动命名管道服务器,并在客户端连接时加载和调用包含折扣代码的程序集,将结果反序列化回客户端线程并从DoAction返回。因此,有很多线程正在等待和序列化,但我看不到一种方法,使它更快C# AppDomain+;命名管道序列化性能,c#,.net,C#,.net,考虑以下情况:在条形码扫描仪下扫描订单,订单号被发送到windows服务应用程序,该应用程序将计算并发回价格。除其他事项外,它还考虑了折扣券,折扣在单独的组件中处理。 我想做的是能够在运行时卸载程序集,这样就可以在不停止服务的情况下替换dll。(服务启动需要30分钟) 所以我想到了创建一个新的AppDomain的想法,它将加载程序集并在其中执行代码。通信是通过命名管道和序列化完成的。 从功能上看,它运行良好,但在生产中性能变得非常低。有人对如何使下面的代码尽可能快地运行有什么建议吗 守则解释:
[Serializable]
internal class ActionLoader
{
private const string DOMAINNAME = "Actions";
private const string PIPE_TO = "PipeTo";
private const string PIPE_BACK = "PipeBack";
private string assemblyName;
private string className;
private string methodName;
private List<object> parameters;
private static BinaryFormatter formatter = new BinaryFormatter();
public ActionLoader(string assemblyName, string className, string methodName, List<object> parameters)
{
this.assemblyName = assemblyName;
this.className = className;
this.methodName = methodName;
this.parameters = parameters;
}
private static AppDomain domain = AppDomain.CreateDomain(DOMAINNAME);
public OrderPrice DoAction()
{
// after clientThread is done it fills RetVal
ThreadedExecuter<OrderPrice> clientThread = new ThreadedExecuter<OrderPrice>(NamedPipeClient, parameters);
clientThread.Start();
if (domain == null) // domain can be unloaded by ropsrefresh so check if it should be created again
{
domain = AppDomain.CreateDomain(DOMAINNAME);
}
// AppDomainCallback runs in the context of appdomain so dll's get loaded in there and not in CurrentDomain
domain.DoCallBack(AppDomainCallback);
clientThread.Thread.Join();
return clientThread.RetVal; // return price deseralized from AppDomain
}
public static void UnloadAppDomain() // called by ropsrefresh => refresh config
{
if (domain != null)
{
AppDomain.Unload(domain);
domain = null;
}
}
private void AppDomainCallback()
{
OrderPrice price = null;
Assembly assembly = Assembly.LoadFrom(assemblyName);
object action = assembly.CreateInstance(className);
MethodInfo mi = action.GetType().GetMethod(methodName);
// using pipes to communicate between AppDomains
using (NamedPipeServerStream stream = new NamedPipeServerStream(PIPE_TO))
{
stream.WaitForConnection();
List<object> parameters = (List<object>)DeserializeFromStream(stream);
Type t = action.GetType();
if (mi != null)
price = (OrderPrice)mi.Invoke(action, parameters.ToArray());
}
// server becomes client to serialize data back
using (NamedPipeClientStream stream = new NamedPipeClientStream(PIPE_BACK))
{
stream.Connect();
SerializeToStream(stream, price);
}
}
private static OrderPrice NamedPipeClient(object parameters)
{
OrderPrice price = null;
// using pipes to communicate between AppDomains
using (NamedPipeClientStream stream = new NamedPipeClientStream(PIPE_TO))
{
stream.Connect();
SerializeToStream(stream, parameters); // serialize function parameters to pipe stream
}
using (NamedPipeServerStream stream = new NamedPipeServerStream(PIPE_BACK))
{
stream.WaitForConnection();
price = (OrderPrice)DeserializeFromStream(stream);
}
return price; // returns deserialized price to ThreadedExecutor
}
private static object DeserializeFromStream(Stream stream)
{
return formatter.Deserialize(stream);
}
private static void SerializeToStream(Stream stream, object parameters)
{
formatter.Serialize(stream, parameters);
}
}
[可序列化]
内部类ActionLoader
{
private const string DOMAINNAME=“Actions”;
专用施工管柱管道\u TO=“PipeTo”;
专用const string PIPE\u BACK=“PipeBack”;
私有字符串名称;
私有字符串类名;
私有字符串methodName;
私有列表参数;
私有静态BinaryFormatter formatter=新的BinaryFormatter();
公共ActionLoader(string assemblyName、string className、string methodName、列表参数)
{
this.assemblyName=assemblyName;
this.className=className;
this.methodName=methodName;
此参数=参数;
}
私有静态AppDomain域=AppDomain.CreateDomain(域名);
公共订单价格操作()
{
//完成clientThread后,它将填充RetVal
ThreadedExecuter clientThread=新的ThreadedExecuter(名称为PipeClient,参数);
clientThread.Start();
if(domain==null)//ropsrefresh可以卸载域,所以请检查是否应该再次创建该域
{
domain=AppDomain.CreateDomain(域名);
}
//AppDomainCallback在appdomain的上下文中运行,因此dll在其中加载,而不是在CurrentDomain中加载
domain.DoCallBack(AppDomainCallback);
clientThread.Thread.Join();
return clientThread.RetVal;//从AppDomain反序列化的返回价格
}
public static void UnloadAppDomain()//由ropsrefresh=>refresh config调用
{
如果(域!=null)
{
卸载(域);
域=空;
}
}
私有void AppDomainCallback()
{
订单价格=空;
Assembly=Assembly.LoadFrom(assemblyName);
对象操作=assembly.CreateInstance(类名);
MethodInfo mi=action.GetType().GetMethod(methodName);
//使用管道在AppDomains之间通信
使用(NamedPipeServerStream=新的NamedPipeServerStream(管道到))
{
stream.WaitForConnection();
列表参数=(列表)反序列化FromStream(流);
类型t=action.GetType();
如果(mi!=null)
price=(OrderPrice)mi.Invoke(action,parameters.ToArray());
}
//服务器变为客户机以将数据序列化回来
使用(NamedPipeClientStream=新的NamedPipeClientStream(管道返回))
{
stream.Connect();
流(流、价格);
}
}
私有静态OrderPrice NamedPipeClient(对象参数)
{
订单价格=空;
//使用管道在AppDomains之间通信
使用(NamedPipeClientStream=新的NamedPipeClientStream(管道到))
{
stream.Connect();
SerializeToStream(流,参数);//将函数参数序列化到管道流
}
使用(NamedPipeServerStream=新的NamedPipeServerStream(管道返回))
{
stream.WaitForConnection();
price=(OrderPrice)反序列化fromstream(stream);
}
返回价格;//将反序列化的价格返回给ThreadedExecutor
}
私有静态对象反序列化FromStream(Stream)
{
返回格式化程序。反序列化(流);
}
私有静态流(流、对象参数)
{
序列化(流、参数);
}
}
重写代码以使用任务库。由于它使用windows线程池,因此性能更好。任务。结果将被阻止,直到任务完成,因此不再需要连接
public OrderPrice DoAction()
{
Task<OrderPrice> task = Task<OrderPrice>.Factory.StartNew(NamedPipeClient);
if (domain == null)
domain = AppDomain.CreateDomain(DOMAINNAME);
domain.DoCallBack(AppDomainCallback);
return task.Result;
}
public orderprise DoAction()
{
Task Task=Task.Factory.StartNew(NamedPipeClient);
如果(域==null)
domain=AppDomain.CreateDomain(域名);
domain.DoCallBack(AppDomainCallback);
返回任务。结果;
}
重写代码以使用任务库。由于它使用windows线程池,因此性能更好。任务。结果将被阻止,直到任务完成,因此不再需要连接
public OrderPrice DoAction()
{
Task<OrderPrice> task = Task<OrderPrice>.Factory.StartNew(NamedPipeClient);
if (domain == null)
domain = AppDomain.CreateDomain(DOMAINNAME);
domain.DoCallBack(AppDomainCallback);
return task.Result;
}
public orderprise DoAction()
{
Task Task=Task.Factory.StartNew(NamedPipeClient);
如果(域==null)
domain=AppDomain.CreateDomain(域名);
domain.DoCallBack(AppDomainCallback);
返回任务。结果;
}