主頁 > 後端開發 > 高性能RPC框架gRPC竟恐怖如斯~

高性能RPC框架gRPC竟恐怖如斯~

2022-09-03 07:10:47 後端開發

大家好,我是不才陳某~

RPC、gRPC、Thrift、HTTP,大家知道它們之間的聯系和區別么?這些都是面試常考的問題,今天帶大家先搞懂 RPC 和 gRPC,

在講述 gRPC 之前,我們需要先搞懂什么是 RPC,

不 BB,直接上文章目錄:

什么是 RPC ?

RPC(Remote Procedure Call Protocol)遠程程序呼叫協議,目標就是讓遠程服務呼叫更加簡單、透明,

RPC 框架負責屏蔽底層的傳輸方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二進制)和通信細節,服務呼叫者可以像呼叫本地介面一樣呼叫遠程的服務提供者,而不需要關心底層通信細節和呼叫程序,

為什么要用 RPC ?

當我們的業務越來越多、應用也越來越多時,自然的,我們會發現有些功能已經不能簡單劃分開來或者劃分不出來,

此時可以將公共業務邏輯抽離出來,將之組成獨立的服務 Service 應用,而原有的、新增的應用都可以與那些獨立的 Service 應用 互動,以此來完成完整的業務功能,

所以我們急需一種高效的應用程式之間的通訊手段來完成這種需求,RPC 大顯身手的時候來了!

常用的 RPC 框架

  • gRPC:一開始由 google 開發,是一款語言中立、平臺中立、開源的遠程程序呼叫(RPC)系統,
  • Thrift:thrift 是一個軟體框架,用來進行可擴展且跨語言的服務的開發,它結合了功能強大的軟體堆疊和代碼生成引擎,以構建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 這些編程語言間無縫結合的、高效的服務,
  • Dubbo:Dubbo 是一個分布式服務框架,以及 SOA 治理方案,Dubbo自2011年開源后,已被許多非阿里系公司使用,
  • Spring Cloud:Spring Cloud 由眾多子專案組成,如 Spring Cloud Config、Spring Cloud Netflix、Spring Cloud Consul 等,提供了搭建分布式系統及微服務常用的工具,

RPC 的呼叫流程

要讓網路通信細節對使用者透明,我們需要對通信細節進行封裝,我們先看下一個 RPC 呼叫的流程涉及到哪些通信細節:

  1. 服務消費方(client)呼叫以本地呼叫方式呼叫服務;
  2. client stub接收到呼叫后負責將方法、引數等組裝成能夠進行網路傳輸的訊息體;
  3. client stub找到服務地址,并將訊息發送到服務端;
  4. server stub收到訊息后進行解碼;
  5. server stub根據解碼結果呼叫本地的服務;
  6. 本地服務執行并將結果回傳給 server stub;
  7. server stub將回傳結果打包成訊息并發送至消費方;
  8. client stub接收到訊息,并進行解碼;
  9. 服務消費方得到最終結果,

RPC 的目標就是要 2~8 這些步驟都封裝起來,讓用戶對這些細節透明,下面是網上的另外一幅圖,感覺一目了然:

什么是 gRPC ?

gRPC 是一個高性能、通用的開源 RPC 框架,其由 Google 2015 年主要面向移動應用開發并基于 HTTP/2 協議標準而設計,基于 ProtoBuf 序列化協議開發,且支持眾多開發語言,

由于是開源框架,通信的雙方可以進行二次開發,所以客戶端和服務器端之間的通信會更加專注于業務層面的內容,減少了對由 gRPC 框架實作的底層通信的關注,

如下圖,DATA 部分即業務層面內容,下面所有的資訊都由 gRPC 進行封裝,

gRPC 的特點

  • 跨語言使用,支持 C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP 等編程語言;
  • 基于 IDL 檔案定義服務,通過 proto3 工具生成指定語言的資料結構、服務端介面以及客戶端 Stub;
  • 通信協議基于標準的 HTTP/2 設計,支持雙向流、訊息頭壓縮、單 TCP 的多路復用、服務端推送等特性,這些特性使得 gRPC 在移動端設備上更加省電和節省網路流量;
  • 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一種語言無關的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 呼叫的高性能;
  • 安裝簡單,擴展方便(用該框架每秒可達到百萬個RPC),

gRPC 互動程序

  • 交換機在開啟 gRPC 功能后充當 gRPC 客戶端的角色,采集服務器充當 gRPC 服務器角色;
  • 交換機會根據訂閱的事件構建對應資料的格式(GPB/JSON),通過 Protocol Buffers 進行撰寫 proto 檔案,交換機與服務器建立 gRPC 通道,通過 gRPC 協議向服務器發送請求訊息;
  • 服務器收到請求訊息后,服務器會通過 Protocol Buffers 解譯 proto 檔案,還原出最先定義好格式的資料結構,進行業務處理;
  • 資料處理完后,服務器需要使用 Protocol Buffers 重編譯應答資料,通過 gRPC 協議向交換機發送應答訊息;
  • 交換機收到應答訊息后,結束本次的 gRPC 互動,

簡單地說,gRPC 就是在客戶端和服務器端開啟 gRPC 功能后建立連接,將設備上配置的訂閱資料推送給服務器端,

我們可以看到整個程序是需要用到 Protocol Buffers 將所需要處理資料的結構化資料在 proto 檔案中進行定義,

Protocol Buffers

你可以理解 ProtoBuf 是一種更加靈活、高效的資料格式,與 XML、JSON 類似,在一些高性能且對回應速度有要求的資料傳輸場景非常適用,

ProtoBuf 在 gRPC 的框架中主要有三個作用:定義資料結構、定義服務介面,通過序列化和反序列化方式提升傳輸效率,

為什么 ProtoBuf 會提高傳輸效率呢?

我們知道使用 XML、JSON 進行資料編譯時,資料文本格式更容易閱讀,但進行資料交換時,設備就需要耗費大量的 CPU 在 I/O 動作上,自然會影響整個傳輸速率,

Protocol Buffers 不像前者,它會將字串進行序列化后再進行傳輸,即二進制資料

可以看到其實兩者內容相差不大,并且內容非常直觀,但是 Protocol Buffers 編碼的內容只是提供給操作者閱讀的,實際上傳輸的并不會以這種文本形式,而是序列化后的二進制資料,位元組數會比 JSON、XML 的位元組數少很多,速率更快,

gPRC 如何支撐跨平臺,多語言呢 ?

Protocol Buffers 自帶一個編譯器也是一個優勢點,前面提到的 proto 檔案就是通過編譯器進行編譯的,proto 檔案需要編譯生成一個類似庫檔案,基于庫檔案才能真正開發資料應用,

具體用什么編程語言編譯生成這個庫檔案呢?由于現網中負責網路設備和服務器設備的運維人員往往不是同一組人,運維人員可能會習慣使用不同的編程語言進行運維開發,那么 Protocol Buffers 其中一個優勢就能發揮出來——跨語言,

從上面的介紹,我們得出在編碼方面 Protocol Buffers 對比 JSON、XML 的優點:

  • 標準的 IDL 和 IDL 編譯器,這使得其對工程師非常友好;
  • 序列化資料非常簡潔,緊湊,與 XML 相比,其序列化之后的資料量約為 1/3 到 1/10;
  • 決議速度非常快,比對應的 XML 快約 20-100 倍;
  • 提供了非常友好的動態庫,使用非常簡單,反序列化只需要一行代碼,

Protobuf 也有其局限性:

  • 由于 Protobuf 產生于 Google,所以目前其僅支持 Java、C++、Python 三種語言
  • Protobuf 支持的資料型別相對較少,不支持常量型別;
  • 由于其設計的理念是純粹的展現層協議(Presentation Layer),目前并沒有一個專門支持 Protobuf 的 RPC 框架,

Protobuf 適用場景:

  • Protobuf 具有廣泛的用戶基礎,空間開銷小以及高決議性能是其亮點,非常適合于公司內部的對性能要求高的 RPC 呼叫
  • 由于 Protobuf 提供了標準的 IDL 以及對應的編譯器,其 IDL 檔案是參與各方的非常強的業務約束;
  • Protobuf 與傳輸層無關,采用 HTTP 具有良好的跨防火墻的訪問屬性,所以 Protobuf 也適用于公司間對性能要求比較高的場景;
  • 由于其決議性能高,序列化后資料量相對少,非常適合應用層物件的持久化場景;
  • 主要問題在于其所支持的語言相對較少,另外由于沒有系結的標準底層傳輸層協議,在公司間進行傳輸層協議的除錯作業相對麻煩,

基于 HTTP 2.0 標準設計

除了 Protocol Buffers 之外,從互動圖中和分層框架可以看到, gRPC 還有另外一個優勢——它是基于 HTTP 2.0 協議的,

由于 gRPC 基于 HTTP 2.0 標準設計,帶來了更多強大功能,如多路復用、二進制幀、頭部壓縮、推送機制,

這些功能給設備帶來重大益處,如節省帶寬、降低 TCP 連接次數、節省 CPU 使用等,gRPC 既能夠在客戶端應用,也能夠在服務器端應用,從而以透明的方式實作兩端的通信和簡化通信系統的構建,

HTTP 1.X 定義了四種與服務器互動的方式,分別為 GET、POST、PUT、DELETE,這些在 HTTP 2.0 中均保留,我們看看 HTTP 2.0 的新特性:雙向流、多路復用、二進制幀、頭部壓縮,

性能對比

與采用文本格式的 JSON 相比,采用二進制格式的 protobuf 在速度上可以達到前者的 5 倍!

Auth0 網站所做的性能測驗結果顯示,protobuf 和 JSON 的優勢差異在 Java、Python 等環境中尤為明顯,下圖是 Auth0 在兩個 Spring Boot 應用程式間所做的對比測驗結果,

結果顯示,protobuf 所需的請求時間最多只有 JSON 的 20% 左右,即速度是其 5 倍!

下面看一下性能和空間開銷對比,

從上圖可得出如下結論:

  • XML序列化(Xstream)無論在性能和簡潔性上比較差,
  • Thrift 與 Protobuf 相比在時空開銷方面都有一定的劣勢,
  • Protobuf 和 Avro 在兩方面表現都非常優越,

gRPC 實戰

1. 專案結構

我們先看一下專案結構:

2. 生成 protobuf 檔案

檔案 helloworld.proto:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

這里提供了一個 SayHello() 方法,然后入參為 HelloRequest,回傳值為 HelloReply,可以看到 proto 檔案只定義了入參和回傳值的格式,以及呼叫的介面,至于介面內部的實作,該檔案完全不用關心,

檔案 pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>rpc-study</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>grpc-demo</artifactId>

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.14.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.14.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.14.0</version>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.14.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>

這里面的 build 其實是為了安裝 protobuf 插件,里面其實有 2 個插件我們需要用到,分別為 protobuf:compile 和 protobuf:compile-javanano,當我們直接執行時,會生成左側檔案,其中 GreeterGrpc 提供呼叫介面,Hello 開頭的檔案功能主要是對資料進行序列化,然后處理入參和回傳值,

可能有同學會問,你把檔案生成到 target 中,我想放到 main.src 中,你可以把這些檔案 copy 出來,或者也可以通過工具生成:

  • 下載 protoc.exe 工具 ,下載地址:https://github.com/protocolbuffers/protobuf/releases
  • 下載 protoc-gen-grpc 插件, 下載地址: http://jcenter.bintray.com/io/grpc/protoc-gen-grpc-java/

3. 服務端和客戶端

檔案 HelloWorldClient.java:

public class HelloWorldClient {
    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());

    public HelloWorldClient(String host,int port){
        channel = ManagedChannelBuilder.forAddress(host,port)
                .usePlaintext(true)
                .build();

        blockingStub = GreeterGrpc.newBlockingStub(channel);
    }


    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public  void greet(String name){
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        try{
            response = blockingStub.sayHello(request);
        } catch (StatusRuntimeException e)
        {
            logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
            return;
        }
        logger.info("Message from gRPC-Server: "+response.getMessage());
    }

    public static void main(String[] args) throws InterruptedException {
        HelloWorldClient client = new HelloWorldClient("127.0.0.1",50051);
        try{
            String user = "world";
            if (args.length > 0){
                user = args[0];
            }
            client.greet(user);
        }finally {
            client.shutdown();
        }
    }
}

這個太簡單了,就是連接服務埠,呼叫 sayHello() 方法,

檔案 HelloWorldServer.java:

public class HelloWorldServer {
    private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());

    private int port = 50051;
    private Server server;

    private void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(new GreeterImpl())
                .build()
                .start();
        logger.info("Server started, listening on " + port);

        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {

                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                HelloWorldServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    // block 一直到退出程式
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        final HelloWorldServer server = new HelloWorldServer();
        server.start();
        server.blockUntilShutdown();
    }

    // 實作 定義一個實作服務介面的類
    private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
        @Override
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            HelloReply reply = HelloReply.newBuilder().setMessage(("Hello " + req.getName())).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
            System.out.println("Message from gRPC-Client:" + req.getName());
            System.out.println("Message Response:" + reply.getMessage());
        }
    }
}

主要是實作 sayHello() 方法,里面對資料進行了簡單處理,入參為 “W orld”,回傳的是 “Hello World”,

4. 啟動服務

先啟動 Server,回傳如下:

再啟動 Client,回傳如下:

同時 Server回傳如下:

原始碼地址:https://github.com/lml200701158/rpc-study

寫在最后

這篇文章其實是我去年寫的,這次是重新整理,文章詳細講解了 RPC 和 gRPC,以及 gRPC 的應用示例,非常全面,后面會再把 Thrift 整理出來,

這個 Demo 看起來很簡單,我 TM 居然搞了大半天,一開始是因為不知道需要執行 2 個不同的插件來生成 protobuf,以為只需要點擊 protobuf:compile 就可以,結果發現 protobuf:compile-javanano 也需要點一下,

如果覺得作者寫的好,有所識訓的話,點個關注,推薦一波,文章首發于公眾號!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/503449.html

標籤:Java

上一篇:用Python做一個中秋節嫦娥投食小游戲《千里嬋娟》

下一篇:x64dbg 實作插件Socket反向通信

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more