C# 同一应用程序的多个实例引发StackOverflow异常
在我的解决方案中,我有3个主要项目(C# 同一应用程序的多个实例引发StackOverflow异常,c#,wpf,stack-overflow,C#,Wpf,Stack Overflow,在我的解决方案中,我有3个主要项目(Server、Client和Special Client)。在我的测试环境中,(1)Special Client每5秒只显示一次买卖/执行订单的计数,(2)Client提交买卖订单,(3)Server处理客户提交的订单并发送回Client和Special Client。如果我按Ctrl+F5启动所有3个应用程序,让Client每10毫秒提交一个订单,所有这些应用程序都可以正常工作,在Windows任务管理器上,我观察到Client的内存使用量在115MB和32
Server
、Client
和Special Client
)。在我的测试环境中,(1)Special Client
每5秒只显示一次买卖/执行订单的计数,(2)Client
提交买卖订单,(3)Server
处理客户提交的订单并发送回Client
和Special Client
。如果我按Ctrl+F5启动所有3个应用程序,让Client
每10毫秒提交一个订单,所有这些应用程序都可以正常工作,在Windows任务管理器上,我观察到Client
的内存使用量在115MB和320MB之间波动,没有一个崩溃(我已经测试了很长时间)
如果我从./Client/bin/Debug/…
中再启动2个客户端
(总共3个客户端
,1个特殊客户端
和1个服务器
),并让每个客户端
每秒提交20个订单,它也可以正常工作(不确定,但可能每个客户端的性能都会略有下降)。但是,如果我从。/Client/bin/Debug/…
启动第四个客户端
,并让每个客户端每秒提交20个订单,我最终会在其中一个客户端
上获得堆栈溢出异常
因此,简言之,一个客户端
可以每秒提交100个订单,并从服务器
获取所有订单,并在一台计算机上以中等复杂的用户界面上显示信息,而在一台计算机上,3个客户端
一起可以每秒处理60个订单,但4个客户端
一起不能每秒处理80个订单
为什么?
编辑
这是我在调用堆栈窗口中得到的消息:
[External Code]
> Client.dll!Client.AsyncObsetion<Data.AllOrder>.OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e) Line 29 C#
[External Code]
Client.dll!Client.ClientCode.UpdateOrderOnExecution(Data.AllOrderStruct order) Line 431 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 390 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
.
.
.
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
Client.dll!Client.ClientCode.Receive(object sender, System.Net.Sockets.SocketAsyncEventArgs e) Line 402 C#
[External Code]
但是我的代码中没有该事件的订户!第431行引用了这一行if(order.ExType==ExecutionType.Full)列表。删除(o);
这段代码:
public class AsyncObsetion<T> : ObservableCollection<T>
{
SynchronizationContext context = SynchronizationContext.Current;
readonly object _lock = new object();
public AsyncObsetion() { BindingOperations.EnableCollectionSynchronization(this, _lock); }
public AsyncObsetion(IEnumerable<T> list) : base(list) { BindingOperations.EnableCollectionSynchronization(this, _lock); }
void RaiseCollectionChanged(object param) => base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
void RaisePropertyChanged(object param) => base.OnPropertyChanged((PropertyChangedEventArgs)param);
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaiseCollectionChanged(e);
else context.Send(RaiseCollectionChanged, e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaisePropertyChanged(e);
else context.Send(RaisePropertyChanged, e);
}
public void InsertRange(IEnumerable<T> items)
{
CheckReentrancy();
foreach (var item in items) Items.Add(item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
void UpdateOrderOnExecution(AllOrderStruct order)
{
bool buyOrder = order.OrderType == OrderType.Buy;
var list = buyOrder ? BuyOrders : SellOrders;
var o = buyOrder ? list.Where(x => x.BuyOrderNo == order.BuyOrderNo).First() : list.Where(x => x.SellOrderNo == order.SellOrderNo).First();
o.ExType = order.ExType;
if (order.ExType == ExecutionType.Full) list.Remove(o);
else
{
var index = list.IndexOf(o);
o.Quantity -= order.QtyTraded;
list[index] = o;
}
AddExecutedOrder(order);
if (order.BrokerBought == BrokerName || order.BrokerSold == BrokerName) UpDatePendingOrders(o);
App.Current.Dispatcher.Invoke(CommandManager.InvalidateRequerySuggested);
}
void Receive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
var data = PacMan<MessageHeader>.Unpack(e.Buffer);
if (data.Type == Message.Trade)
{
e.SetBuffer(orderBuffer, 0, orderBuffer.Length);
e.AcceptSocket.Receive(e.Buffer);
var order = PacMan<AllOrderStruct>.Unpack(e.Buffer);
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
else
{
SetBuffer(e, data.Size);
e.AcceptSocket.Receive(e.Buffer);
var array = e.Buffer.ToArray();
Task.Run(() => AddNews(array));
}
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e);
}
else Disconnect4mServer(null);
}
第390行引用这一行case Data.Action.Execute:UpdateOrderOnExecution(order);break;
和402行引用这一行if(!e.AcceptSocket.ReceiveAsync(e))Receive(null,e);
这段代码:
public class AsyncObsetion<T> : ObservableCollection<T>
{
SynchronizationContext context = SynchronizationContext.Current;
readonly object _lock = new object();
public AsyncObsetion() { BindingOperations.EnableCollectionSynchronization(this, _lock); }
public AsyncObsetion(IEnumerable<T> list) : base(list) { BindingOperations.EnableCollectionSynchronization(this, _lock); }
void RaiseCollectionChanged(object param) => base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
void RaisePropertyChanged(object param) => base.OnPropertyChanged((PropertyChangedEventArgs)param);
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaiseCollectionChanged(e);
else context.Send(RaiseCollectionChanged, e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == context) RaisePropertyChanged(e);
else context.Send(RaisePropertyChanged, e);
}
public void InsertRange(IEnumerable<T> items)
{
CheckReentrancy();
foreach (var item in items) Items.Add(item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
void UpdateOrderOnExecution(AllOrderStruct order)
{
bool buyOrder = order.OrderType == OrderType.Buy;
var list = buyOrder ? BuyOrders : SellOrders;
var o = buyOrder ? list.Where(x => x.BuyOrderNo == order.BuyOrderNo).First() : list.Where(x => x.SellOrderNo == order.SellOrderNo).First();
o.ExType = order.ExType;
if (order.ExType == ExecutionType.Full) list.Remove(o);
else
{
var index = list.IndexOf(o);
o.Quantity -= order.QtyTraded;
list[index] = o;
}
AddExecutedOrder(order);
if (order.BrokerBought == BrokerName || order.BrokerSold == BrokerName) UpDatePendingOrders(o);
App.Current.Dispatcher.Invoke(CommandManager.InvalidateRequerySuggested);
}
void Receive(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
var data = PacMan<MessageHeader>.Unpack(e.Buffer);
if (data.Type == Message.Trade)
{
e.SetBuffer(orderBuffer, 0, orderBuffer.Length);
e.AcceptSocket.Receive(e.Buffer);
var order = PacMan<AllOrderStruct>.Unpack(e.Buffer);
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
else
{
SetBuffer(e, data.Size);
e.AcceptSocket.Receive(e.Buffer);
var array = e.Buffer.ToArray();
Task.Run(() => AddNews(array));
}
e.SetBuffer(headerBuffer, 0, headerBuffer.Length);
if (!e.AcceptSocket.ReceiveAsync(e)) Receive(null, e);
}
else Disconnect4mServer(null);
}
void接收(对象发送方,SocketAsyncEventArgs e)
{
if(e.bytesttransfered>0&&e.SocketError==SocketError.Success)
{
var数据=PacMan.Unpack(如缓冲区);
if(data.Type==Message.Trade)
{
e、 SetBuffer(orderBuffer,0,orderBuffer.Length);
e、 AcceptSocket.Receive(如缓冲区);
var订单=PacMan.Unpack(如缓冲区);
开关(命令动作)
{
case Data.Action.Add:AddNewOrder(订单);break;
case Data.Action.Delete:RemoveOrder(订单);break;
案例数据.Action.Modify:修改订单(订单);中断;
case Data.Action.Execute:UpdateOrderOnExecution(订单);break;
}
}
其他的
{
SetBuffer(e,数据大小);
e、 AcceptSocket.Receive(如缓冲区);
var array=e.Buffer.ToArray();
Task.Run(()=>AddNews(数组));
}
e、 SetBuffer(headerBuffer,0,headerBuffer.Length);
如果(!e.AcceptSocket.ReceiveAsync(e))接收(null,e);
}
else断开与服务器的连接(null);
}
你应该使用多线程方法我看不出你的代码有任何问题,因为你同时使用3个项目尝试使用多线程,让cpu为你处理它Charles的“迭代”关键字给了我一个黑点子。对于任何有兴趣解决这类问题的人,这里是我的黑点子ch与堆:
1) 在客户端
和特殊客户端
中创建这三个变量:
Queue<byte[]> Orders = new Queue<byte[]>();
Timer orderProcessTimer;
bool OPTstarted;
3) 初始化构造函数中的orderProcessTimer
,设置processing inverval并将其挂接到订单处理函数中:
orderProcessTimer = new Timer(500);
orderProcessTimer.Elapsed += ProcessOrder;
void ProcessOrder(object sender, EventArgs e)
{
orderProcessTimer.Stop();
var count = Orders.Count;
if(count > 0)
{
for (int i = 0; i < count; i++)
{
var order = PacMan<AllOrderStruct>.Unpack(Orders.Dequeue());
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
}
orderProcessTimer.Start();
}
4) 执行ProcessOrder
功能中耗时的任务:
orderProcessTimer = new Timer(500);
orderProcessTimer.Elapsed += ProcessOrder;
void ProcessOrder(object sender, EventArgs e)
{
orderProcessTimer.Stop();
var count = Orders.Count;
if(count > 0)
{
for (int i = 0; i < count; i++)
{
var order = PacMan<AllOrderStruct>.Unpack(Orders.Dequeue());
switch (order.Action)
{
case Data.Action.Add: AddNewOrder(order); break;
case Data.Action.Delete: RemoveOrder(order); break;
case Data.Action.Modify: ModifyOrder(order); break;
case Data.Action.Execute: UpdateOrderOnExecution(order); break;
}
}
}
orderProcessTimer.Start();
}
void ProcessOrder(对象发送方,事件参数e)
{
orderProcessTimer.Stop();
var count=订单数;
如果(计数>0)
{
for(int i=0;i
UpdateOrderOnExecution
处理订单和在订单视图中制作实时价格-数量图表所需的时间最多
它可以工作,但我可能不会采用这种方法,我会让运行这种类型应用程序的机器成为半堆栈机器,以提高性能。发布生成堆栈的代码overflow@Charles,编辑了帖子,我将解决方案作为zip文件发布。有时调用堆栈窗口引用其他方法,但所有这些调用都来自Receive
回调。@Charles,要开始测试:首先,您必须在窗口左下角的TextBox
中指定一个名称,标题为Client
和Special Client
,第二次单击连接按钮,第三次单击启动测试按钮。要更改从Client
自动提交订单的时间间隔,请打开名为Client
的项目的ClientCode.cs
,在末尾附近您将看到#region MockTest
,您将看到void startTest(object obj)
方法并更改此行的时间间隔timer=new dispatchermer(){Interval=new TimeSpan(0,0,0,0,0,100)};
该方法的问题在于接收函数,即递归调用的模式receive