我为商务创建了一个C#控制台服务器和WinForms客户端。
(纠正我,如果我错了,我做了很多的研究。所以我可能会混淆某些话题。)
在服务器上,我已经了解到使用Socket.BegingReceive
方法最好使用AsyncCallback
。由于它使用ThreadPool
类。多线程客户端同时还重用线程等(而不是在单线程设置或每个客户端的线程上进行while循环。(我已经读过这些具有特定的缺点,我不感兴趣。)) p>
基本上我所追求的是确保如果我正在制作的应用程序突然爆炸并且10万(甚至1,000,000?!)人们同时使用它,它将为每个客户保持良好和稳定的连接
服务器: Intel i5 4 Core:服务器处理另一台服务器上的MYSQL请求并将其提供给格式化的客户端他们会期待的。
客户端: 无限制的硬件资源:在浏览表单时要求服务器提供数据以填写表单。
所以我担心:让我们说4个客户端连接并请求服务器进程数据,大约需要5秒钟来处理MYSQL数据库(我知道,这就像处理速度的生命周期一样)。 (最糟糕的情况等))。如果第五个客户连接怎么办?这意味着ThreadPool必须创建另一个线程来保存此进程。现在让这些数字更大,我有100个同时客户端请求确切的长期运行方法。在4核CPU上。所以现在ThreadPool花费了十几秒甚至更长的时间来创建所有这些新线程。
编辑:缩小问题范围:
如何为FindPrimeNumbers调用实现异步编程。 (该方法是搜索数据库(不同服务器上的MySQL,如果有帮助的话)。)
我该怎么做以防止这种情况发生?我如何使这更直观。如何防止大型负载可能产生糟糕的用户体验等等。
FindPrimerNumber方法就像数据库调用一样。
class Program
{
private static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> clientSockets = new List<Socket>();
private static CancellationTokenSource CancelSource = new CancellationTokenSource();
private static CancellationToken CancelToken = CancelSource.Token;
private const int BUFFER_SIZE = 2048;
private const int PORT = 100;
private static readonly byte[] buffer = new byte[BUFFER_SIZE];
static void Main()
{
SetupServer();
Console.ReadLine();
CloseAllSockets();
}
private static void SetupServer()
{
serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
serverSocket.Listen(0);
serverSocket.BeginAccept(BeginAcceptCallback, null);
}
private static void CloseAllSockets()
{
foreach (Socket socket in clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
serverSocket.Close();
}
private static void BeginAcceptCallback(IAsyncResult AR)
{
Socket socket = serverSocket.EndAccept(AR);
clientSockets.Add(socket);
socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, BeginReceiveCallback, socket);
Console.WriteLine("Client connected!");
serverSocket.BeginAccept(BeginAcceptCallback, null);
}
private static void BeginReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int receivedInt = current.EndReceive(AR);
byte[] received = new byte[receivedInt];
Array.Copy(buffer, received, receivedInt);
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, BeginReceiveCallback, current);
string text = Encoding.ASCII.GetString(received);
int number = 0;
if (text.ToLower() == "exit")
{
current.Shutdown(SocketShutdown.Both);
current.Close();
clientSockets.Remove(current);
Console.WriteLine("Client Disconnected");
return;
}
else if (int.TryParse(text, out number))
{
int num = FindPrimeNumber(number);
byte[] data = Encoding.ASCII.GetBytes(num.ToString());
current.Send(data);
Console.WriteLine("Prime Number: "+num+" :Sent");
}
else
{
current.Send(Encoding.ASCII.GetBytes("Not a Command"));
}
}
//VERY LONG CPU FUNCTION
public static int FindPrimeNumber(int n)
{
//Connect to database (MySQL Database on a different server, if that makes a difference)
//Send Query
//Read Return
return queryReturn()
}
}
答案 0 :(得分:2)
您运行线程这一事实并不意味着该线程必须在核心上消耗100%的时钟周期。启动诊断工具(进程查看器或其他东西)并查看计算机上的线程数:它将是数百个。然后查看总CPU消耗:它将接近零。绝大多数线程花费大部分时间做任何事情,只等待其他事情发生。
另一方面,如果在数据库服务器上执行的查询花费的时间长达5秒,则会遇到麻烦,因为这意味着您对它施加了太大的压力,因此无论并行化如何,整个系统都将受到影响。
这些都是非常基本的东西,所以如果你还没有掌握它,那么担心它是不合时宜和不切实际的。只需做你必须做的事情,然后担心性能。