《WebKit 技术内幕》学习之十四(1):调式机制

第14章 调试机制

        支持调试HTML、CSS和JavaScript代码是浏览器或者渲染引擎需要提供的一项非常重要的功能,这里包括两种调试类型:其一是功能,其二是性能。功能调试能够帮助HTML开发者使用单步调试等技术来查找代码中的问题,性能调试能够采集JavaScript代码、网络等性能瓶颈。当然,这只是对于HTML开发者来说的。因为对于性能而言,问题可能存在于HTML代码,也可能是浏览器本身的问题。为此,Chromium的工程师开发出另外一套机制——“Tracing”技术,它能够收集Chromium内部代码的工作方式和性能瓶颈,以帮助定位Chromium本身的问题。

1 Web Inspector

1.1 基本原理

在之前的多个章节中,Chromium的开发者工具被用来帮助了解渲染引擎和浏览器背后的原理,这一工具实际上是基于WebKit的Web Inspector技术开发出来的,它的功能很丰富,这里将和大家一起了解背后的机制。图14-1是Chromium浏览器的开发者工具调试网页的界面示意图。

                                图14-1 使用开发者工具调试网页的用户界面

         图14-1主要包括上下两个部分,上半部分表示需要被调试的网页,下半部分表示调试器的界面,该界面是由WebKit提供的,这也就是说,使用了WebKit的内核就可以看到类似的界面,不同点在于Chromium使用了多进程架构。根据WebKit中的定义,上面的部分称为后端(Backend),下面的部分称为前端(Frontend),这一叫法会一直贯穿整个章节。

        图14-1还有一个显著的特点,那就是调试器的界面本身也是使用HTML、CSS和JavaScript技术来编写的,听起来很酷吧?后面会详细介绍调试器的工作方式。

Chromium开发者工具提供了众多的功能,主要包括以下几种。

  • 元素审查(EIements) :该功能能够帮助开发者查看每一个DOM元素,如图中查看“body”元素,同样可以查看它的样式信息。
  • 资源(Resources) :该功能能够帮助开发者查看各种资源信息,如内部存储、Cookie、离线缓存等。
  • 网络(Network) :该功能能够帮助开发者了解和诊断网络功能和性能,这个在第4章中曾经使用过。
  • JavaScript代码(Sources) :就是调试JavaScript代码,同其他语言的调试器一样,它能够设置断点、单步调试JavaScript语句等。
  • 时间序列(TimeIine) :该功能能够按照时间次序来收集网页消耗的内存、绘制的帧数和生成各种事件,帮助开发者分析网页性能。
  • 性能收集器(ProfiIes) :它能够收集JavaScript代码使用CPU的情况、JavaScript堆栈、CSS选择器等信息,以帮助开发者分析网页的运行行为。
  • 诊断器(Audits) :这是帮助开发者分析网页可能存在的问题或者可以改善的地方。
  • 控制台(ConsoIe):该控制台可以输入JavaScript语句,由JavaScript引擎计算出结果。插件“PageSpeed” :笔者自行安装的帮助分析网页性能问题的工具,它能够帮助全方位分析各种可能的优化点,它不是Chromium浏览器的默认功能,而是需要开发者自己去Chrome Web Store或其他地方下载。

1.2 协议

        调试机制的前端和后端通过使用一定格式的数据来进行通信,这些数据使用JSON格式来表示。具体到如何理解数据的内容,那就是Web Inspector使用的特殊调试协议,该协议定义了如何理解双方发送的数据内容。在WebKit中,协议被定义在Inspector.json文件中(Blink则是protocol.json文件),而遵照该协议传输的数据同样使用JSON格式,下面将详细分析该协议。

        图14-2是定义Web Inspector的前端和后端交互信息的协议,如上面所说,该协议使用的是一个JSON格式的文档。从全局来看,协议中主要包括两个属性,一个是“version”,用来表示协议的版本号,Web Inspector有多个版本,需要注意的是版本的兼容性问题,图14-2中显示的是版本1.0。另一个是“domains”,它定义了多个协议细节,并包含了多个“domain”,一个“domain”通常是一类功能,如“memory”、“CSS”等。下面再来了解“domain”的定义。

                                图14-2 Web Inspector的协议定义

        一个“domain”包括6个属性,前三个比较简单,容易理解,后面三个比较复杂,较难理解。下面着重介绍后面三个属性。

  • 第一个是“types”,它有点像预先定义的类型,这些类型表示一些特定的数据,在后面的定义中可以声明使用这些类型来表示一定的数据结构,例如图中定义“id”为“StyleSheetId”,它表示的是一个字符串。在第二个属性“commands”中可以看到对它们的引用。
  • 第二个属性“commands”定义“domain”中包含的所有命令,这些命令类似于远程过程调用,表示前端和后端之间发送请求并响应的方式。如图中的“toggleProperty”就是一个命令的定义,可以看到它定义了参数的名称和类型,对于第一个参数它引用了“CSSStyleId”,这就是之前定义在“types”中的一个类型(图中没有写出来)。该命令还包括一个或者多个返回值,跟参数类似的定义。
  • 最后一个属性是“events”,它是用来描述事件的,同样可以包含一个或者多个事件,主要是向对方发送当前的一些状态信息,与命令不同的是,它没有也不需要返回值。图中所示是一个表示样式表变化的事件。

        上面介绍的都是一些抽象的定义,下面通过一个具体的例子说明一下,估计读者就能理解透彻了。图14-3是用户单击取消一个CSS属性(也就是使它不再生效)的时候,WebKit背后发生的各种函数调用和时间派发的过程,实际上是一系列的JSON格式的数据,而这些数据当然是遵守上面协议中的具体定义的。

                图14-3 Web Inspector取消CSS属性值涉及的前后端信息交换

        当用户在单击取消一个CSS属性值的时候,在WebKit内部其实已经发生了多个消息的传递,这其中包含命令和事件,也包括返回值。首先最为直接的就是数据是使用JSON格式表示的,然后对每条消息,笔者都加入了标注表示是前端到后端或者后端到前端来方便理解,后面使用“{}”括起来的部分就是实际传输的数据。

        第一个数据就是从前端到后端的命令,其含义是将“id”为“9”的样式表中的属性索引值为0的属性禁用,根据图14-2中的定义,该命令需要返回值,为了标记返回值,在发送JSON数据的时候,附加了一个“id”为“1532”的标记,这样,当后端发送返回值的时候,前端就能够知道这是哪个请求的回复,而不会出现理解错误的情况。所以,对于不需要返回值的命令或者本身就没有返回值的事件而言,就不需要这样的“id”标记。例如,第二和第三条就是从后端到前端的数据,就是一个DOM属性改变的事件,其中并不包含这样的标记信息。

        第四条就是第一条命令的返回值,如前所述,包含了返回数据和第一条命令的标记。后面基本上是因为样式变化带来的请求,原理同上面所说的非常类似,由此过程可以看出,用户一个简单的操作,需要带来前后端大量的操作,其中这些命令主要是前端发送给后端,而事件主要是后端告诉前端当前的一些状态信息。

1.3 WebKit内部机制

        介绍了Web Inspector的协议和基本工作方式之后,下面有必要深入到WebKit和Chromium代码中来理解它们内部的工作机制,本节主要介绍WebKit中的基础设施,包括前后端的支持情况。前面介绍了前后端只是通过消息传递来完成调试功能的,不依赖于其他框架,所以这一节将重点介绍架构中是如何发送、接收消息及其支撑的架构,首先看前端调试器。

调试器界面本身也是使用Web技术来实现的,前面介绍的所有功能都是使用最新HTML5技术来完成的,目前有两个接口需要具体WebKit移植的实现,第一是发送消息到后端的接口,第二是从对方接收消息后,将消息派发给调试器。图14-4是WebInspector前端的主要结构和基础设施。

                                图14-4 WebInspector前端的主要结构

        最上层的是Inspector.html,也就是读者看到的调试器主界面,完全采用HTML5技术。因为调试器包含众多的功能,所以它实际上使用了各种功能的JavaScript代码。在其典型的三个JavaScript文件中,首先是InspectorFrontendAPI,它是前端的公共接口,被上层的调试器包含的JavaScript代码使用,同时该类也包括公共的派发消息的接口;然后是inspector.js,它是一个总的入口,包括所有主要对象的创建;而InspectorBackend.js是一个背后的具体实现类,它能够提供接口来将消息发送到被调试的网页,也就是后端。

        调试器主要需要两个能力,一是发送消息给前端,二是接收后端的消息。这两个接口在WebInspector框架中被定义,图14-4中左边就是发送消息给前端的过程。Web Inspector使用一个称为InspectorFrontendHost的类作为接口,当然它本身没有具体实现。在一般的情况下(如为远程调试,则稍有不同,后面会介绍),InspectorFrontendHost是一个使用C++编写的接口类,它通过V8的绑定机制来实现,最后会调用到InspectorFrontendHost,之后就依赖于具体移植的实现了。另外一个接口就是定义了派发消息的JavaScript接口,也就是InspectorFrontendAPI.js定义的派发消息的两个接口,在Web Inspector中,一个默认的实现是InspectorClient类中有一个静态方法,该方法使用ScriptController类,将通过C++代码获得的消息传入JavaScript代码,这样整个前端依赖的两个本地接口就得到了完美地实现,不仅如此,该结构还能很好地满足之后的远程调试的需求,是非常棒的结构。

                前端介绍完之后就是后端,如图14-5描述的后端所需要的主要类和它们的关系。同前端不一样的是,后端的主要功能都是使用C++代码来完成的,其中最重要的类是InspectorController,它控制着后端的所有动作及其和被调试网页之间的联系。InspectorClientroller类包含一个InspectorClient对象,该对象负责实现基础功能,如情况缓存、高亮等。同时,它包含一个主要的对外接口,那就是dispatchMessageFromFrontend类,它由WebKit移植将前端的消息传递给后端的时候被调用,这些消息都是由InspectorBackendDispatcherImpl这个自动生成类处理的,这个类能够处理所有的请求消息,并解析这些消息,然后转换成相应的C++对象和函数的调用。可是怎么做到这一点的呢?很简单,每个“domain”都会有相应的称为CommandHandler的类,如图中CSSCommandHandler类。每个类的对象都会注册到InspectorBackendDispatcherImpl对象中,根据图14-3所述的消息,该对象很容易知道调用的“domain”、命令或者事件等。InspectorBackendDispatcherImpl类也能够同V8等JavaScript引擎交互,典型的应用就是审查(Inspect)一个元素,用户单击一个元素的时候(可以从后端的被调试网页中单击),JavaScript引擎接收到事件,然后处理并调用该类来处理。本身CommandHandler类包含一些接口,以图中CSSCommandHandler类为例,它的具体实现类是InspectorCSSAgent,借助于一些其他设施类,它能够知道被调试网页有关CSS方面的信息,如借用InspectorStyleSheet类。

                                图14-5 WebInspector后端的主要结构

        图中的InspectorBaseAgent是支持所有功能的子类,由于Web Inspector需要众多功能,如前面介绍的CSS、内存、性能等,所有这些功能都是基于该类实现的,这些类的对象使用一个注册类来管理,如图中的InspectorAgentRegistry类。

        以与CSS相关的Agent为例,该类被调用后能够做正确的处理并按需返回相应的结果。但是,这里不进行消息的编码,而是使用一个InspectorFrontend自动生成类来帮助这些C++对象和数据转换成JSON格式的数据。

        另外一方面就是后端发送消息到前端,WebKit定义了一个抽象接口就是InspectorFrontendChannel类。顾名思义,它就是一个传输通道,所有后端到前端的消息都是从它传出的,消息本身不做任何转换,只是传输数据。InspectorFrontend是一个自动生成的类,这里是一个模拟前端的工具类,由于它是一个根据协议自动生成的类,后端调用协议中定义的方法和事件,而该类提供这些接口并将调用转变成JSON格式,包括命令的名称、参数等信息。转换后的JSON字符串通过通道传出,从而完成了消息的发送过程。

        通过上面的介绍,相信读者已经推测出前后端之间的通信框架,因为WebKit的特殊性,WebCore只是提供框架,具体实现交由移植来完成。图14-6是基本的通信框架。

图14-6 WebInspector的前后端通信框架示意图

        图中左边是前端,右边是后端,通信框架主要定义前后端的一些用来双向通信的基础类和提供的接口。这些接口需依赖实际的通信机制才能完成,设想一下如果前后端都工作在一个进程中,那么非常简单,只需将消息传递到另一线程中即可,不需要复杂的机制。不过,这里它只是定义了抽象接口,而没有定义通信方面的具体规定,这为跨进程的调试机制和远程调试提供了可能。

1.4 Chromium开发者工具

        Chromium开发者工具(通常见到的称谓是DevTools)是基于Web Inspector机制的一套跨进程的调试工具,具体用法笔者稍后会介绍,这里先来理解它是如何基于Web Inspector来实现的。

        因为Chromium的多进程架构,后端中被调试的网页是一个Renderer进程,前端的网页同样也是一个Renderer进程。根据前面Web Inspector的架构,Chromium所要做的是将前后端的通信机制连接起来。由于Chromium架构的特殊性,消息的传递实际上经过了一个中转站,那就是Browser进程,也就是说这两个Renderer进程不是直接通信的,而是将消息传递给Browser进程,由它再派发给相应的Renderer进程。

        图14-7描述了Chromium支持多进程调试的整个架构,上半部分是前端和后端两个Renderer进程,而下半部分是Browser进程,整个架构可以说非常简洁明确。首先来看前端的接收和发送消息是如何被支持的。首先是Chromium对前端发送消息到后端的支持。WebKit中的基类InspectorFrontHost类其实是调用InspectorFrontendClient类来发送消息的,而WebKit的Chromium移植做了一个具体的实现类Inspector-FrontendClientImpl类,该类会调用WebDevToolsFrontendImpl类。最后的跨进程通信类是content::DevToolsClient,该类是Chromium项目中用于开发者工具的进程间通信类。然后是Chromium对前端接收来自后端消息的支持。当WebDevToolsFrontendImpl类接收到content::DevToolsClient传递过来消息的时候,它直接通过V8提供的机制调用InspectorFrontendAPI.js的dispatchMessage方法。经过这一过程,Chromium已经将WebInspector的两个用于传递消息的接口实现了。

                                图14-7 Chromium DevTools多进程架构

        接下来是Browser进程,每个前端进程都有一个相应的DevTools-FrontendHost对象。当前端的一个消息到达时,如何找到其相应的后端呢?答案是DevToolsManagerImpl类,它管理了所有的“前后端对”,实际上包含了两个哈希表,第一个是从前端到后端的映射,第二个是相反方向的映射。有了这两个哈希表,一切就很简单了,Browser进程只是将前端的消息根据映射关系找到后端并传递给它,相反方向也是一样的,这就是图14-7中描述的过程。

        最后是后端进程的工作过程。content::DevToolsAgent也是负责同Browser进程交互消息的具体实现类,包括接收和发送。在这之上主要是WebKit的Chromium移植提供的接口,其具体的实现是通过WebDevToolsAgentImpl类,它会将接收的消息传递给InspectorController,至此,Chromium连接上WebKit中后端接收消息的处理机制。而对于发送消息,WebDevToolsAgentImpl是InspectorFrontendChannel的子类,会实现sendMessageToFrontend接口。这样,双向过程完整地得到了支持。

1.5 远程调试

        何谓远程调试(Remote Debugging)?刚刚上面介绍的都是在同一个浏览器中的进程,虽然可能在不同的进程中。远程调试是指前端和后端在不同的浏览器实例中,但这两个实例可能在同一个环境中,也可能在不同的环境中。例如,两台机器,甚至网络上的两个设备。

        根据前面描述的Web Inspector机制,本身Web Inspector机制没有定义通信的方式,而且前后端只是通过JSON消息和一定的协议来交互的,所以从理论上来讲,远程调试也只是需要建立一定的通信方式就能够支持远程调试,好消息是现在已经得到实现了。

        Web Inspector没有提供或者规定远程调试的方式,在Chromium中,远程调试得到了比较好的支持,其具体的做法如下。

  1. 首先在后端所在的浏览器中需要建立一个HTTP服务器,在桌面系统上,建立和打开TCP监听一个端口,如9222。然后在另外一个Chromium浏览器实例中输入“http://localhost:9222”就可以看到被调试的网页。目前,这种方式并不支持网络上的不同机器,可能是实现者考虑到安全性问题。如果调试Android平台上的Chrome浏览器中的网页,首先需要将Android设备通过USB连接上开发机器,这时候用户可以在Android上Chrome浏览器的设置中打开远程调试开关,这一操作实际上创建了一个Unix Domain Socket。此时,开发者在Linux系统中只要打开Chrome浏览器(必须大于版本33)并在地址栏输入“chrome://respect”就能够看到需要调试的网页了。
  2. 建立连接之后,通过HTTP协议将被调试网页的HTML、CSS和JS等资源文件从被调试网页所在的浏览器传输到前端调试器所在的网页中。
  3. 当开始调试时,前端调试器会尝试使用Web Socket建立前端和后端传输消息的通道。这是一种基于Web的新技术,能够建立类似于套接字的数据传输通道。

        图14-8描述了使用WebSocket技术来传输调试消息的远程调试机制。根据前面介绍的WebKit中前端和后端传输消息的机制,主要是InspectorFrontendHost(前端使用)和InspectorFrontendChannel(后端使用)这两个类,它们具体的实现由子类来完成,在远程调试中,通信的基础设施是由HTML5的WebSocket技术来支撑的,那么Chromium中如何使用该技术呢?道理很简单,就是将InspectorFrontendHost接口同时暴露到JavaScript中,当本地代码需要发送消息的时候,通过调用InspectorFrontendHost类的本地接口,而这个本地接口已经同JavaScript中的实际发送接口连接起来,这样本地代码中的消息就能够使用WebSocket技术来发送了,示例代码14-1是Chromium中连接本地代码和Javascript代码发送消息的部分代码节选,这个代码是前端的代码。而对于接收消息,同样比较简单,Chromium将WebSocket的onMessage事件同后端的消息派发函数连接起来,确实轻而易举。对于后端而言,它使用C++代码来完成WebSocket的连接,原理是类似的。

图14-8 使用WebSocket技术的远程调试

示例代码14-1 使用WebSocket建立连接的远程调试机制

    WebInspector.loaded = function() {// 首先构建ws,这个是WebSocket的URL,下面是创建WebSocket对象if (ws) {WebInspector.socket = new WebSocket(ws);// 接收对方过来的消息,直接交给相应的模块去处理WebInspector.socket.onmessage=function(message) {InspectorBackend.dispatch(message.data);   }WebInspector.socket.onerror = function(error) { console.error(error); }WebInspector.socket.onopen = function() {// 当连接打开后,就将InspectorFrontendHost的发送消息InspectorFrontendHost.sendMessageToBackend =WebInspector.socket.send.bind(WebInspector.socket);WebInspector.doLoadedDone();}…}}

        Weinre是一个支持远程调试功能的开源项目,它除了能够支持WebInspector协议,还能够支持Firebug(Firefox的调试工具)的协议,其原理也是类似的,有兴趣的读者可以自行查阅相关技术文档。

1.6 Chromium Tracing机制

        Chromium开发者工具能够帮助Web开发者理解网页运行过程中的行为并帮助分析一些性能问题。但是,如果出现问题,特别是绘制网页的时候,开发者非常希望了解为什么Chromium会使用如此多的时间,笔者相信Chromium开发者工具很难回答这样的问题。同时,对于Chromium的开发者来说,如果需要分析Chromium自身问题,就需要相应的工具来帮助分析,在Chromium中,chrome://tracing这一诊断工具能够满足上面的要求。

        这是一个基于事件收集的分析工具,它能够帮助诊断一些WebKit和Chromium内部代码在绘制网页过程中存在的问题,其中最主要的还是同图形相关的操作。我们在第7章中的4.3节中使用过该工具来分析渲染过程。

        这一机制的实现采用的思想非常简单,Tracing机制在Chromium代码中插入相应的跟踪代码,然后计算开始和结束之间的时间差,虽然简单,但是非常有用,典型的例子如下所示。

    TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")doSomethingCostly()TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")

        Tracing机制在某个动作执行前加入“开始事件”代码,然后在动作结束后加入“结束事件”代码,机制中的TRACE_EVENT宏自动计算获得该动作执行的时间。当然,一般典型的例子是在函数或者一段代码开始的时候加入TRACE_EVENT0,在该函数退出时候,该事件自动记录下结束的时间,这是使用对象的自动析构机制来完成的。这样Tracing机制就能够计算出该函数运行所需要的时间,而不再需要额外插入结束代码,如示例代码14-2所示的三个记录点。

        示例代码14-2首先在函数入口处创建Tracing对象并记录时间点,在该函数退出时,对象析构前就能够自动记录整个函数执行的总时间。然后在第一个“if”语句中,又加入了一个记录点记录了这种条件下的时间消耗,后面的Tracing对象也是同样的原理。

示例代码14-2 Chromium合成器中的ThreadProxy类代码片段

    bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect)  {TRACE_EVENT0("cc", "ThreadProxy::CompositeAndReadback");DCHECK(IsMainThread());DCHECK(layer_tree_host_);if (defer_commits_) {TRACE_EVENT0("cc", "CompositeAndReadback_DeferCommit");return false;}if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded()) {TRACE_EVENT0("cc", "CompositeAndReadback_EarlyOut_LR_Uninitialized");return false;}…}

        在第7章中,我们已经介绍过如何使用该诊断工具来收集数据,这里不再重复。回顾图7-15中chrome://tracing收集的一段时间内的跟踪事件集合,开发者可以看到各个进程内的时间分布情况,它同时也显示了各个线程的函数调用情况,从中能够发现热点区域,也就是耗时特别长的函数。该工具还能够支持保存这些数据,这样可以很方便地传播这些数据,并获得他人的分析帮助。

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

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

相关文章

Spring Boot 模块工程(通过 Maven Archetype)建立

前言 看到我身边的朋友反馈说,IDEA 新建项目时,如果通过 Spring Initializr 来创建 Spring Boot , 已经无法选择 Java 8 版本,通过上小节的教程,不知道该如何创建 Spring Boot 模块工程。如下图所示: 一.IDEA 搭建 …

Kafka(八)使用Kafka构建数据管道

目录 1 使用场景2 构建数据管道时需要考虑的问题2.1 及时性2.2 可靠性高可用可靠性数据传递 2.3 高吞吐量2.4 数据格式2.5 转换ETLELT 2.6 安全性2.7 故障处理2.8 耦合性和灵活性临时数据管道元数据丢失末端处理 3 使用Connect API3.1 Connect的数据处理流程sourcesinkconnecto…

IP组播地址

目录 1.硬件组播 2.因特网范围内的组播 IP组播地址让源设备能够将分组发送给一组设备。属于多播组的设备将被分配一个组播组IP地址 组播地址范围为224.0.0.0~239.255.255.255(D类地址),一个D类地址表示一个组播组。只能用作分组的目标地址。源地址总是为单播地址…

丝路昆仑文物展:启用网关,文物预防性保护设备数据无缝对接平台

一、多功能网关数据无缝流转 近日,“丝路昆仑——新疆文物精品展”在天津博物馆开展。展览分为三部分:“丝路前奏”、“丝路华响”和“丝路梵音”,前两部分是以张骞凿通西域前后的中原西域两地文化交流,第三部分则讲述了佛教沿西…

【并发】什么是 Future?

🍎个人博客:个人主页 🏆个人专栏:JAVA ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 关键特性和操作包括: 提交任务: 查询完成状态: 等待结果: 取消任务&#xff1a…

golang整合rabbitmq,创建交换机并绑定队列

1,如果要开发消息队列,需要创建交换机和队列,通常有2中方式创建,1种是在面板直接创建 2,第二种就是在代码中创建,这里 展示的是go语言代码中创建rabbitmq package mainimport ("fmt""log""github.com/streadway/amqp" )func main() {// 连接R…

年销180万辆的特斯拉,护城河却在崩塌

文|刘俊宏 2023年率先开启汽车价格战的马斯克,伤敌一百自损八千? 在1月25日的特斯拉2023Q4财报电话会上,特斯拉CEO马斯克对中国公司的竞争力如此感叹道,“要是没有贸易壁垒,他们将摧毁(destroy…

SpringBlade微服务开发平台

采用前后端分离的模式,前端开源两个框架:Sword (基于 React、Ant Design)、Saber (基于 Vue、Element-UI)后端采用SpringCloud全家桶,并同时对其基础组件做了高度的封装,单独开源出一个框架:BladeToolBladeTool已推送至…

Git--创建仓库(1)

git init Git 使用 git init 命令来初始化一个 Git 仓库,Git 的很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令。 在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有…

通俗易懂理解SegNet语义分割模型

重要说明:本文从网上资料整理而来,仅记录博主学习相关知识点的过程,侵删。 一、参考资料 深度学习之图像分割—— SegNet基本思想和网络结构以及论文补充 一文带你读懂 SegNet(语义分割) 二、相关介绍 1. 上采样(…

vue3中使用markdown编辑器

首先安装 npm i md-editor-v3 Setup 模板 <template><MdEditor v-model"text" /> </template><script setup> import { ref } from vue; import { MdEditor } from md-editor-v3; import md-editor-v3/lib/style.css;const text ref(Hell…

R语言-检验正态性

1.为什么要检验正态性 首先需要明确正态性与正态分布是有区别的&#xff0c;正态分布&#xff08;标准分布&#xff09;是统计数据的分布方式&#xff0c;是个钟形曲线&#xff0c;已平均值为对称轴&#xff0c;数据在对称轴两侧对称分布。正态性是检验实际数据与标准正态分布…

消息中间件之八股面试回答篇:一、问题概览+MQ的应用场景+RabbitMQ如何保证消息不丢失(生产者确认机制、持久化、消费者确认机制)+回答模板

问题概览 目前主流的消息队列技术&#xff08;MQ技术&#xff09;分为RabbitMQ和Kafka&#xff0c;其中深蓝色为只要是MQ&#xff0c;一般都会问到的问题。浅蓝色是针对RabbitMQ的特性的问题。蓝紫色为针对Kafka的特性的问题。 MQ的应用场景 MQ主要提供的功能为&#xff1a;异…

Linux shell编程学习笔记42:hdparm命令

ChatGPT 和文心一言哪个更好用&#xff1f; 从智能回复、语言准确性、知识库丰富度等方面比较&#xff0c;两大AI助手哪个更胜一筹&#xff1f;快来和我们分享一下你的看法吧~ 0 前言 获取硬盘序列号是信息资产管理和信息安全检测中经常要收集的信息&#xff0c;对于Linux来说…

Unity - 将项目转为HDRP

Camera window -> Package Manager 之后会出现HDRP向导窗口&#xff0c;均点击修复。 在Edit中&#xff0c;更改项目中的材质

景联文科技大模型数据集更新!教育题库新增高质量数学题、逻辑推理题及英文题

苏格拉底曾以“点燃火焰”的理念来诠释教育。随着大语言模型在教育中的不断应用&#xff0c;教育与AI的深度融合&#xff0c;让我们看到了“点燃火焰”的理念的更多可能性。 大语言模型可以通过与学生的互动&#xff0c;为他们提供个性化的学习体验&#xff0c;更好地满足学习需…

目标检测数据集 - MS COCO

文章目录 1. 数据集介绍2. 使用pycocotools读取数据3. 验证mAP 论文&#xff1a;Microsoft COCO: Common Objects in Context 网址&#xff1a;https://arxiv.org/abs/1405.0312 官网&#xff1a;https://cocodataset.org/ 1. 数据集介绍 MS COCO是一个非常大型&#xff0c;且…

音频特效SDK,满足内容生产的音频处理需求

美摄科技&#xff0c;作为音频处理技术的佼佼者&#xff0c;推出的音频特效SDK&#xff0c;旨在满足企业内容生产中的音频处理需求。这款SDK内置多种常见音频处理功能&#xff0c;如音频变声、均衡器、淡入淡出、音频变调等&#xff0c;帮助企业轻松应对各种音频处理挑战。 一…

网安培训第二期——sql注入+中间件+工具

文章目录 宽字节注入插入注入二次注入PDO模式(动态靶机&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;)sql注入读取文件sql注入导出文件linux命令 10.12笔记sqlmapsqlmap参数 10.13笔记sqlmap 文件读写前后缀常用tamper及适用场景 10.…