提升服务器性能的两种方法

在处理大量对象(例如10,000个对象)时,通常需要解决两大性能问题:对象的大内存分配和服务器的长时间响应。为了解决这些问题,有两种可以提高服务器端性能的方法:C#中的迭代模式和HTTP中的分块传输编码。在接下来的部分中,将探讨这些方法如何帮助解决这两个问题,并提供两个从服务器端到客户端流式传输数组的示例。

C#中的迭代模式

众所周知,可以通过在具有IEnumerable(T)返回类型的方法或属性中使用yield关键字来启用迭代模式。该模式的理念是逐个枚举项目,而不是返回整个集合。

public IEnumerable<ReturnModel> Get() { // 返回大量对象的示例 foreach (var i in Enumerable.Range(0, 10000)) { yield return new ReturnModel() { SequenceNumber = i, ID = Guid.NewGuid() }; } }

由于枚举在foreach循环开始时就开始,而不需要等待所有对象都准备好,通常可以预期效率和内存使用会更好。

HTTP中的分块传输编码

分块传输编码是一种机制,允许服务器“逐块”返回数据。在编码中,数据由每个十六进制数字后跟一个\r\n分隔,这告诉客户端后续块的长度。下面是一个由Mozilla开发者网络提供的服务器响应示例,它由三行组成,每行都是一个块。

HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked 7\r\n Mozilla\r\n 9\r\n Developer\r\n 7\r\n Network\r\n 0\r\n \r\n

由于数据旨在以一系列块的形式发送,而不是整个数据,因此省略了常规的Content-Length头部。

服务器端示例

以下代码片段展示了一个Web API方法传输大型JSON数组。Get方法以之前看过的迭代模式返回每个对象。自定义的HTTP消息处理程序将在返回流开始之前启用分块传输编码。

// 省略命名空间 namespace WebApplication1.Controllers { public class ValuesController : ApiController { [HttpGet] public IEnumerable<ReturnModel> Get() { // 返回大量对象的示例 foreach (var i in Enumerable.Range(0, 10000)) { yield return new ReturnModel() { SequenceNumber = i, ID = Guid.NewGuid() }; } } } public class Handler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = base.SendAsync(request, cancellationToken); response.Result.Headers.TransferEncodingChunked = true; return response; } } }

以下代码片段展示了如何将自定义HTTP消息处理程序添加到集合中。

// 省略命名空间 namespace WebApplication1 { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API配置和服务 // Web API路由 config.MapHttpAttributeRoutes(); config.MessageHandlers.Add(new Handler()); } } }

客户端示例

// 省略命名空间 namespace ConsoleApp1 { class Program { static void Main(string[] args) { Console.WriteLine("Press any key to continue..."); Console.ReadKey(true); foreach (var value in GetValues()) { Console.WriteLine("{0}\t{1}", value.SequenceNumber, value.ID); } Console.ReadKey(true); } static IEnumerable<ReturnModel> GetValues() { var serializer = new JsonSerializer(); var client = new HttpClient(); var header = new MediaTypeWithQualityHeaderValue("application/json"); client.DefaultRequestHeaders.Accept.Add(header); // 注意:端口号可能不同。 using (var stream = client.GetStreamAsync("http://localhost:63025/api/values").Result) using (var sr = new StreamReader(stream)) using (var jr = new JsonTextReader(sr)) { while (jr.Read()) { if (jr.TokenType != JsonToken.StartArray && jr.TokenType != JsonToken.EndArray) { yield return serializer.Deserialize<ReturnModel>(jr); } } } } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485