《ASP.NET Core 6框架揭秘》实例演示[21]:如何承载你的后台服务

借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中。任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,ASP.NET Core应用最终也体现为这样一个承载服务。[本文节选《ASP.NET Core 6框架揭秘》第14章]

[S1401]利用承载服务收集性能指标(源代码)
[S1402]依赖注入的应用(源代码)
[S1403]配置选项的应用(源代码)
[S1404]提供针对环境的配置(源代码)
[S1405]日志的应用(源代码)
[S1406]在配置中定义日志过滤规则(源代码)

[S1401]利用承载服务收集性能指标

承载服务的项目一般会采用“Microsoft.NET.Sdk.Worker”这个SDK。服务承载模型涉及的接口和类型大都定义在“Microsoft.Extensions.Hosting.Abstractions”这个NuGet包,而具体实现在由NuGet包“Microsoft.Extensions.Hosting”来提供。我们演示的承载服务会定时采集当前进程的性能指标并将其分发出去。我们只关注处理器使用率、内存使用量和网络吞吐量这三种典型的指标,为此我们定义了如下这个PerformanceMetrics类型。我们并不会实现真正的性能指标收集,定义的静态方法Create会利用随机生成的指标来创建PerformanceMetrics对象。

public class PerformanceMetrics
{private static readonly Random _random = new();public int     Processor { get; set; }public long Memory { get; set; }public long Network { get; set; }public override string ToString() => @$"CPU: {Processor * 100}%; Memory: {Memory / (1024* 1024)}M; Network: {Network / (1024 * 1024)}M/s";public static PerformanceMetrics Create() => new(){Processor = _random.Next(1, 8),Memory     = _random.Next(10, 100) * 1024 * 1024,Network = _random.Next(10, 100) * 1024 * 1024};
}

承载服务通过IHostedService接口表示,该接口定义的StartAsync和StopAsync方法可以启动与关闭服务。我们将性能指标采集服务定义成如下这个PerformanceMetricsCollector类型。在实现的StartAsync方法中,我们一个定时器每隔5秒调用Create方法创建一个PerformanceMetrics对象,并将它承载的性能指标输出到控制台上。作为定期的Timer对象会在StopAsync方法中被释放。

public sealed class PerformanceMetricsCollector : IHostedService
{private IDisposable? _scheduler;public Task StartAsync(CancellationToken cancellationToken){_scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5),TimeSpan.FromSeconds(5));return Task.CompletedTask;static void Callback(object? state)=> Console.WriteLine($"[{DateTimeOffset.Now}]{PerformanceMetrics.Create()}");}public Task StopAsync(CancellationToken cancellationToken){_scheduler?.Dispose();return Task.CompletedTask;}
}

服务承载系统通过IHost接口表示承载服务的宿主,该对象在应用启动过程中采用Builder模式由对应的IHostBuilder对象来构建。HostBuilder类型是对IHostBuilder接口的默认实现,所以我们采用如下方式创建一个HostBuilder对象,并调用其Build方法来提供作为宿主的IHost对象。在调用Build方法构建IHost对象之前,我们调用了ConfigureServices方法将PerformancceMetricsCollector注册成针对IHostedService接口的服务,并将生命周期模式设置成Singleton。

using App;
new HostBuilder()
.ConfigureServices(svcs => svcs.AddSingleton<IHostedService, PerformanceMetricsCollector>()).Build().Run();

我们最后调用Run方法启动通过IHost对象表示的承载服务宿主,进而启动由它承载的PerformancceMetricsCollector服务,该服务将以图1所示的形式每隔5秒在控制台上输出“采集”的性能指标。

d694ce5ba2b71f2c7e72d0dff3ea0a50.png
图1 承载指标采集服务

除了采用一般的服务注册方式,我们还可以按照如下的方式调用IServiceCollection接口的AddHostedService<THostedService>扩展方法来对承载服务PerformanceMetricsCollector进行注册。我们一般也不会通过调用构造函数的方式创建HostBuilder对象,而是使用定义在Host类型中的 工厂方法CreateDefaultBuilder创建来构建IHostBuilder对象。

using App;
Host.CreateDefaultBuilder(args).ConfigureServices(svcs => svcs.AddHostedService<PerformanceMetricsCollector>()).Build().Run();

[S1402]依赖注入的应用

服务承载系统整合依赖注入框架,针对承载服务的注册实际上就是将它注册到依赖注入框架中。既然承载服务实例最终是通过依赖注入容器提供的,那么它自身所依赖的服务当然也可以进行注册。我们接下来将PerformanceMetricsCollector提供的性能指标收集功能分解到由四个接口表示的服务中,IProcessorMetricsCollector、IMemoryMetricsCollector和INetworkMetricsCollector接口代表的服务分别用于收集三种对应的性能指标,而IMetricsDeliverer接口表示的服务则负责将收集的性能指标发送出去。

public interface IProcessorMetricsCollector
{int GetUsage();
}
public interface IMemoryMetricsCollector
{long GetUsage();
}
public interface INetworkMetricsCollector
{long GetThroughput();
}public interface IMetricsDeliverer
{Task DeliverAsync(PerformanceMetrics counter);
}

我们定义的MetricsCollector类型实现了三个性能指标采集接口,采集的性能指标直接来源于通过静态方法Create创建的PerformanceMetrics对象。MetricsDeliverer类型实现了IMetricsDeliverer接口,实现的DeliverAsync方法直接将PerformanceMetrics对象承载的性能指标输出到控制台上。

public class MetricsCollector :IProcessorMetricsCollector,IMemoryMetricsCollector,INetworkMetricsCollector
{long INetworkMetricsCollector.GetThroughput() => PerformanceMetrics.Create().Network;int IProcessorMetricsCollector.GetUsage() => PerformanceMetrics.Create().Processor;long IMemoryMetricsCollector.GetUsage() => PerformanceMetrics.Create().Memory;
}public class MetricsDeliverer : IMetricsDeliverer
{public Task DeliverAsync(PerformanceMetrics counter){Console.WriteLine($"[{DateTimeOffset.UtcNow}]{counter}");return Task.CompletedTask;}
}

由于整个性能指标的采集工作被分解到四个接口表示的服务之中,所以我们可以采用如下所示的方式重新定义承载服务类型PerformanceMetricsCollector。如代码片段所示,我们在构造函数中注入四个依赖服务,StartAsync方法利用注入的IProcessorMetricsCollector、IMemoryMetricsCollector和INetworkMetricsCollector对象采集对应的性能指标,并利用IMetricsDeliverer对象将其发送出去。

public sealed class PerformanceMetricsCollector : IHostedService
{private readonly IProcessorMetricsCollector _processorMetricsCollector;private readonly IMemoryMetricsCollector _memoryMetricsCollector;private readonly INetworkMetricsCollector _networkMetricsCollector;private readonly IMetricsDeliverer _MetricsDeliverer;private IDisposable? _scheduler;public PerformanceMetricsCollector(IProcessorMetricsCollector processorMetricsCollector,IMemoryMetricsCollector memoryMetricsCollector,INetworkMetricsCollector networkMetricsCollector,IMetricsDeliverer MetricsDeliverer){_processorMetricsCollector = processorMetricsCollector;_memoryMetricsCollector = memoryMetricsCollector;_networkMetricsCollector = networkMetricsCollector;_MetricsDeliverer = MetricsDeliverer;}public Task StartAsync(CancellationToken cancellationToken){_scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));return Task.CompletedTask;async void Callback(object? state){var counter = new PerformanceMetrics{Processor = _processorMetricsCollector.GetUsage(),Memory       = _memoryMetricsCollector.GetUsage(),Network   = _networkMetricsCollector.GetThroughput()};await _MetricsDeliverer.DeliverAsync(counter);}}public Task StopAsync(CancellationToken cancellationToken){_scheduler?.Dispose();return Task.CompletedTask;}
}

在调用IHostBuilder接口的Build方法将IHost对象构建出来之前,包括承载服务在内的所有服务都可以通过它的ConfigureServices方法进行了注册。修改后的程序启动之后同样会在控制台上看到图1所示的输出结果。

using App;
var collector = new MetricsCollector();
Host.CreateDefaultBuilder(args).ConfigureServices(svcs => svcs.AddHostedService<PerformanceMetricsCollector>().AddSingleton<IProcessorMetricsCollector>(collector).AddSingleton<IMemoryMetricsCollector>(collector).AddSingleton<INetworkMetricsCollector>(collector).AddSingleton<IMetricsDeliverer, MetricsDeliverer>()).Build().Run();

[S1403]配置选项的应用

真正的应用开发基本都会使用到配置选项,比如我们演示程序中性能指标采集的时间间隔就应该采用配置选项来指定。由于涉及对性能指标数据的发送,所以最好将发送的目标地址定义在配置选项中。如果有多种传输协议可供选择,就可以定义相应的配置选项。.NET应用推荐采用Options模式来使用配置选项,所以可以定义如下这个MetricsCollectionOptions类型来承载三种配置选项。

public class MetricsCollectionOptions
{public TimeSpan CaptureInterval { get; set; }public TransportType Transport { get; set; }public Endpoint DeliverTo { get; set; }
}public enum TransportType
{Tcp,Http,Udp
}public class Endpoint
{public string Host { get; set; }public int Port { get; set; }public override string ToString() => $"{Host}:{Port}";
}

传输协议和目标地址使用在MetricsDeliverer服务中,所以我们对它进行了如下的修改。如代码片段所示,我们在构造函数中利用注入的IOptions<MetricsCollectionOptions>服务来提供上面的两个配置选项。在实现的DeliverAsync方法中,我们将采用的传输协议和目标地址输出到控制台上。

public class MetricsDeliverer : IMetricsDeliverer
{private readonly TransportType _transport;private readonly Endpoint          _deliverTo;public MetricsDeliverer(IOptions<MetricsCollectionOptions> optionsAccessor){var options = optionsAccessor.Value;_transport = options.Transport;_deliverTo = options.DeliverTo;}public Task DeliverAsync(PerformanceMetrics counter){Console.WriteLine($"[{DateTimeOffset.Now}]Deliver performance counter {counter} to {_deliverTo} via {_transport}");return Task.CompletedTask;}
}

承载服务类型PerformanceMetricsCollector同样应该采用这种方式来提取表示性能指标采集频率的配置选项。如下所示的代码片段是PerformanceMetricsCollector采用配置选项后的完整定义。

public sealed class PerformanceMetricsCollector : IHostedService
{private readonly IProcessorMetricsCollector _processorMetricsCollector;private readonly IMemoryMetricsCollector _memoryMetricsCollector;private readonly INetworkMetricsCollector _networkMetricsCollector;private readonly IMetricsDeliverer _metricsDeliverer;private readonly TimeSpan _captureInterval;private IDisposable? _scheduler;public PerformanceMetricsCollector(IProcessorMetricsCollector processorMetricsCollector,IMemoryMetricsCollector memoryMetricsCollector,INetworkMetricsCollector networkMetricsCollector,IMetricsDeliverer metricsDeliverer,IOptions<MetricsCollectionOptions> optionsAccessor){_processorMetricsCollector = processorMetricsCollector;_memoryMetricsCollector = memoryMetricsCollector;_networkMetricsCollector = networkMetricsCollector;_metricsDeliverer = metricsDeliverer;_captureInterval = optionsAccessor.Value.CaptureInterval;}public Task StartAsync(CancellationToken cancellationToken){_scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5), _captureInterval);return Task.CompletedTask;async void Callback(object? state){var counter = new PerformanceMetrics{Processor = _processorMetricsCollector.GetUsage(),Memory = _memoryMetricsCollector.GetUsage(),Network = _networkMetricsCollector.GetThroughput()};await _metricsDeliverer.DeliverAsync(counter);}}public Task StopAsync(CancellationToken cancellationToken){_scheduler?.Dispose();return Task.CompletedTask;}
}

配置文件配置选项的常用来源,所以我们在根目录下添加了一个名为appsettings.json的配置文件,并在其中定义如下内容来提供上述三个配置选项。由Host类型的CreateDefaultBuilder工厂方法创建的IHostBuilder对象会自动加载这个配置文件。

{"MetricsCollection": {"CaptureInterval": "00:00:05","Transport": "Udp","DeliverTo": {"Host": "192.168.0.1","Port": 3721}}
}

我们接下来对演示程序做相应的改动。之前针对依赖服务的注册是通过调用IHostBuilder对象的ConfigureServices方法利用作为参数的Action<IServiceCollection>对象完成的,该接口还有一个ConfigureServices方法重载,它的参数类型为Action<HostBuilderContext, IServiceCollection>,作为输入的HostBuilderContext上下文可以提供表示应用配置的IConfiguration对象。

using App;
var collector = new MetricsCollector();
Host.CreateDefaultBuilder(args).ConfigureServices((context, svcs) => svcs.AddHostedService<PerformanceMetricsCollector>().AddSingleton<IProcessorMetricsCollector>(collector).AddSingleton<IMemoryMetricsCollector>(collector).AddSingleton<INetworkMetricsCollector>(collector).AddSingleton<IMetricsDeliverer, MetricsDeliverer>().Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection"))).Build().Run();

我们利用提供的Action<HostBuilderContext, IServiceCollection>委托通过调用IServiceCollection接口的Configure<TOptions>扩展方法从提供的HostBuilderContext对象中提取出配置,并对MetricsCollectionOptions配置选项做了绑定。我们修改后的程序运行之后在控制台上会输出如图2所示结果。

6f147ea3eba81fb76db622833cf64f9f.png
图2 引入配置选项

[S1404]提供针对环境的配置

应用程序总是针对某个具体环境进行部署的,开发(Development)、预发(Staging)和产品(Production)是三种典型的部署环境,这里的部署环境在服务承载系统中统称为承载环境(Hosting Environment)。一般来说,不同的承载环境往往具有不同的配置选项,下面我们将演示如何为不同的承载环境提供相应的配置选项。具体的做法很简单:将共享或者默认的配置定义在基础配置文件(如appsettings.json)中,将差异化的部分定义在针对具体环境的配置文件(如appsettings.staging.json和appsettings.production.json)中。对于我们演示的实例来说,我们可以采用图3所示的方式添加额外的两个配置文件来提供针对预发环境和产品环境的差异化配置。

11b37870282677ccc3a80ce38f56d215.png
图3 针对承载环境的配置文件

对于演示实例提供的三个配置选项来说,假设针对承载环境的差异化配合仅限于发送的目标终结点(IP地址和端口),我们就可以采用如下方式将它们定义在针对预发环境的appsettings.staging.json和针对产品环境的appsettings.production.json中。

appsettings.staging.json:

{"MetricsCollection": {"DeliverTo": {"Host": "192.168.0.2","Port": 3721}}
}

appsettings.production.json:

{"MetricsCollection": {"DeliverTo": {"Host": "192.168.0.3","Port": 3721}}
}

由于我们在调用Host的CreateDefaultBuilder方法时传入了命令行参数(args),所以默认创建的IHostBuilder会将其作为配置源。也正因为如此,我们可以采用命令行参数的形式设置当前的承载环境(对应配置名称为“environment”)。如图4所示,我们分别指定不同的承载环境先后四次运行我们的程序,从输出的IP地址可以看出,应用程序确实是根据当前承载环境加载对应的配置文件的。输出结果还体现了另一个细节,那就是默认采用的是产品(Production)环境。

cb9f48b3ccf1b2f76de43383f805ee8e.png
图4 针对承载环境加载配置文件

[S1405]日志的应用

应用开发中不可避免地会涉及很多针对“诊断日志”的应用,我们接下来就来演示承载服务如何记录日志。对于我们的演示实例来说,用于发送性能指标的MetricsDeliverer对象会将收集的指标数据输出到控制台上,下面将这段文字以日志的形式进行输出,为此我们将这个类型进行了如下的修改。

public class MetricsDeliverer : IMetricsDeliverer
{private readonly TransportType _transport;private readonly Endpoint _deliverTo;private readonly ILogger _logger;private readonly Action<ILogger, DateTimeOffset, PerformanceMetrics, Endpoint, TransportType, Exception?> _logForDelivery;public MetricsDeliverer(IOptions<MetricsCollectionOptions> optionsAccessor, ILogger<MetricsDeliverer> logger){var options = optionsAccessor.Value;_transport = options.Transport;_deliverTo = options.DeliverTo;_logger = logger;_logForDelivery = LoggerMessage.Define<DateTimeOffset, PerformanceMetrics, Endpoint, TransportType>(LogLevel.Information, 0, "[{0}]Deliver performance counter {1} to {2} via {3}");}public Task DeliverAsync(PerformanceMetrics counter){_logForDelivery(_logger, DateTimeOffset.Now, counter, _deliverTo, _transport, null);return Task.CompletedTask;}
}

如上面的代码片段所示,我们利用构造函数中注入了的ILogger<MetricsDeliverer>对象并来记录日志。为了避免对同一个消息模板的重复解析,我们可以使用LoggerMessage类型定义的委托对象来输出日志,这也是MetricsDeliverer中采用的编程模式。运行修改后的程序会控制台上的输出如图5所示的结果。由输出结果可以看出,这些文字是由我们注册的ConsoleLoggerProvider提供的ConsoleLogger对象输出到控制台上的。由于承载系统自身在进行服务承载过程中也会输出一些日志,所以它们也会输出到控制台上。

44f2960d2e8e1cd92f7fde3d51f9abf7.png
图5 将日志输出到控制台上

[S1406]在配置中定义日志过滤规则

如果需要对输出的日志进行过滤,可以将过滤规则定义在配置文件中。为了避免在“产品”环境因输出过多的日志影响性能,我们在appsettings.production.json配置文件中以如下的形式将类别以“Microsoft.”为前缀的日志(最低)等级设置为 Warning。

{"MetricsCollection": {"DeliverTo": {"Host": "192.168.0.3","Port": 3721}},"Logging": {"LogLevel": {"Microsoft": "Warning"}}
}

如果此时分别针对开发(Development)环境和产品(Production)环境以命令行的形式启动修改后的应用程序,就会发现针对开发环境控制台会输出类型前缀为“Microsoft.”的日志,但是在针对产品环境的控制台上却找不到它们的踪影。

5ca7e250881258c642df47f89893d547.png
图6 根据承载环境过滤日志

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282965.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用DBCA工具创建自己的数据库

ylbtech-Oracle&#xff1a;使用DBCA工具创建自己的数据库 DBCA创建数据库 默认安装的Oracle数据库一般不能满足实际应用的需求&#xff0c;例如数据库名称、数据库块的大小等都需要修改&#xff0c;那么我们应该自己创建一个满足实际应用系统需要的Oracle数据实例&#xff08;…

免去架构算法调优,如何让你的系统风驰电掣?|图说

通用计算场景下的云服务器领域从来都是兵家必争之地&#xff0c;价格战曾打了一波又一波&#xff0c;可用户痛点却依然是“顽疾”。由于采用的基础硬件、架构和调优技术千差万别&#xff0c;类似配置的云服务器之间存有较大的性能差异。 但市面上五花八门的云服务器不绝于耳&am…

记一次 .NET 某数控机床控制程序 卡死分析

一&#xff1a;背景 1. 讲故事前段时间有位朋友微信上找到我&#xff0c;说它的程序出现了卡死&#xff0c;让我帮忙看下是怎么回事&#xff1f; 说来也奇怪&#xff0c;那段时间求助卡死类的dump特别多&#xff0c;被迫训练了一下对这类问题的洞察力 &#x1f604;&#x1f60…

ASP.NETCoreWeb开发之OptionsPattern

这节我们来讲一下&#xff0c;在ASP.NET Core Web开发中&#xff0c;读取配置文件信息的新方式&#xff1a;Options。前言 /Options在ASP.NET Web框架中&#xff0c;我们读取配置文件中的数据&#xff0c;在不使用第三方框架的情况下&#xff0c;可能需要通过ConfigurationMana…

SpringMVC执行流程图

2019独角兽企业重金招聘Python工程师标准>>> 转载于:https://my.oschina.net/u/2607324/blog/827946

CentOS 7系统安装配置图解教程

操作系统&#xff1a;CentOS 7.3 备注&#xff1a; CentOS 7.x系列只有64位系统&#xff0c;没有32位。生产服务器建议安装CentOS-7-x86_64-Minimal-1611.iso版本 一、安装CentOS 7.3 成功引导系统后&#xff0c;会出现下面的界面 界面说明&#xff1a; Install CentOS 7 #安装…

这份《.NET/C#面试手册》超神啦!

这几天给.neter们整理了一份《.NET/C#面试手册》&#xff0c;目前大约4万字左右&#xff0c;初衷也很简单&#xff0c;就是希望在面试的时候能够帮助到大家&#xff0c;减轻大家的负担和节省时间。对于没有跳槽打算的也可以复习一下相关知识点&#xff0c;就当是查缺补漏&#…

Dinic算法----最大流常用算法之一

——没有什么是一个BFS或一个DFS解决不了的&#xff1b;如果有&#xff0c;那就两个一起。 最大流的$EK$算法虽然简单&#xff0c;但时间复杂度是$O(nm^2)$&#xff0c;在竞赛中不太常用。 竞赛中常用的$Dinic$算法和$SAP$&#xff0c;其实也不太难。 那么&#xff0c;$Dinic$算…

javascript学习笔记 null和undefined

null是javascript语言的关键字&#xff0c;它表示一个特殊值&#xff0c;常用来描述“空值”。对null执行typeof预算&#xff0c;结果返回字符串“object”&#xff0c;也就是说&#xff0c;可以将null认为是一个特殊的对象值&#xff0c;含义是“非对象”。但实际上&#xff0…

C# 为什么高手都是用IsNullOrWhiteSpace对字符串判空?

判断字符串为空有好几种方法&#xff1a;方法一&#xff1a; 代码如下&#xff1a;static void Main(string[] args){string str "";if (str ""){Console.WriteLine("a is empty"); ;}Console.ReadKey();}运行结果&#xff1a;a is empty这样…

Blazor University (51)依赖注入 —— 拥有多个依赖项:错误的方式

原文链接&#xff1a;https://blazor-university.com/dependency-injection/component-scoped-dependencies/owning-multiple-dependencies-the-wrong-way/拥有多个依赖项&#xff1a;错误的方式OwningComponentBase[1] 类是一个合适的解决方案&#xff0c;当我们需要我们的组件…

Centos 7 搭建.net web项目

现在的.NET Core 1.0版本是一个很小的核心&#xff0c;APIs和工具也并不完整&#xff0c;但是随着.Net Core的不断完善&#xff0c;补充的Apis和创新也会一起整合到.NET Framework中。 安装centos系统 请自行安装或百度教程 安装 libicu包 和 dotnet 温馨提示&#xff1a;如果需…

IDEA 快捷注释

1. 新建类的注释模板 1) File->settings->Editor->Live Templates 2) 点击绿色号&#xff0c;选择template group &#xff0c;输入group的name&#xff0c;然后点ok 3) 选中刚才添加的group,点击号,选择live Template 4) 代码模板位置,个人用的代码: 1 /** 2 * &…

matlab 如何hidden,Matlab基本函数-hidden函数

1、hidden函数&#xff1a;设置或取消隐藏线模式2、用法说明(1)hidden on 函数对当前图形打开隐藏线条删除&#xff0c;使网格图后面的线条被前面的线条遮住。设置曲面图形对象的属性FaceColor为坐标轴背景颜色&#xff1b;(2)hidden off 函数对当前图形关闭隐藏线条删除&#…

异常处理,究竟是处理什么

“系统中每行代码&#xff0c;都应该是有意义的&#xff0c;如果一段代码可有可无&#xff0c;那它就不应该存在。”01—内容简述异常处理是软件开发的必备技能&#xff0c;但“异常处理&#xff0c;究竟是处理什么&#xff1f;”&#xff0c;很多小伙伴并没有一个清晰的认识&a…

第十一篇:(顺序)容器的好伴侣 --- 容器适配器

前言 vector容器的数据结构原型是顺序表&#xff0c;它很好的实现了顺序表的功能&#xff0c;大大方便了编程。好了&#xff0c;现在假设有天我又想用栈&#xff0c;那么有没有栈对应的容器呢&#xff1f;很遗憾&#xff0c;木有。但基于“栈”可以由顺序表或者链表实现这一特性…

第一季度ADC市场份额揭榜 A10 Networks再获用户青睐

近日&#xff0c;根据全球知名咨询公司IDC 发布的2018年第一季度中国ADC市场分析报告显示&#xff0c;A10 Networks 稳占中国ADC市场份额第二名。数据来源&#xff1a;IDC 2018年Q1 ADC市场报告 从厂商排名来看依次为 F5 30%, A10Networks 12%, DPtech 12% ,Sangfor 9% &#…

利用linux shell自己主动顶贴

在论坛上面发帖问个什么东西的话&#xff0c;一旦不顶。帖子就秒沉了&#xff0c;可是又实在不想每时每刻都去顶&#xff0c;怎么办&#xff1f;以下展示了怎样利用shell 的crontab实现自己主动顶贴。 闲话不多说了&#xff0c;以豆瓣为例—– 1&#xff1a; 用chrome打开豆瓣…

深度学习库 SynapseML for .NET 发布0.1 版本

2021年11月 微软开源一款简单的、多语言的、大规模并行的机器学习库 SynapseML&#xff08;以前称为 MMLSpark&#xff09;&#xff0c;以帮助开发人员简化机器学习管道的创建。具体参见[1]微软深度学习库 SynapseML&#xff1a;可直接在系统中嵌入 45 种不同机器学习服务、支持…

支持回调处理 php函数,PHP支持回调的函数有哪些?

PHP支持回调的函数有&#xff1a;1、匿名函数&#xff0c;代码为【$server->on Request】&#xff1b;2、类静态方法&#xff0c;代码为【static function test $req】&#xff1b;3、函数&#xff0c;代码为【my_onRequest $req】。PHP支持回调的函数有&#xff1a;1、匿名…