主頁 > 後端開發 > 支持JDK19虛擬執行緒的web框架,之二:完整開發一個支持虛擬執行緒的quarkus應用

支持JDK19虛擬執行緒的web框架,之二:完整開發一個支持虛擬執行緒的quarkus應用

2022-11-02 06:42:44 後端開發

歡迎訪問我的GitHub

這里分類和匯總了欣宸的全部原創(含配套原始碼):https://github.com/zq2599/blog_demos

本篇概覽

  • 本篇是《支持JDK19虛擬執行緒的web框架》系列的第二篇,前文咱們體驗了有虛擬執行緒支持的web服務,經過測驗,發現性能上它與其他兩種常見web架構并無明顯區別,既然如此,還有必要研究和學習嗎?
  • 當然有必要,而且還要通過實戰更深入了解虛擬執行緒與常規執行緒的區別,在各大框架和庫廣泛支持虛擬執行緒之前,打好理論和實踐基礎,這才是本系列的目標
  • 為了接下來的深入了解,咱們先在本篇打好基礎:詳細說明前文的web功能是如何開發出來的
  • 為了突出重點,這里先提前劇透,從編碼的角度說清楚如何開啟虛擬執行緒支持,其實非常簡單,如下圖,左側是quarkus框架下的一個普通web服務,每收到一個web請求,是由執行緒池中的執行緒負責回應的,右側的web服務多了個@RunOnVirtualThread注解,就變成了由新建的虛擬執行緒去處理web請求,沒錯,在quarkus框架下使用虛擬執行緒就是這么簡單

image-20221019081651928

  • 在前文中,我們通過回傳值也看到了上述兩個web服務中,負責web回應的執行緒的不同,如下所示,從執行緒名稱上很容易看出執行緒池和虛擬執行緒的區別

image-20221019083324043

  • 看到這里,您可能會說:就這?一個注解就搞定的事情,你還要寫一篇文章?這不是在浪費作者你自己和各位讀者的時間嗎?

  • 確實,開啟虛擬執行緒,編碼只要一行,然而就目前而言,虛擬執行緒是JDK19專屬,而且還只是預覽功能,要想在實際運行的時候真正開啟并不容易,需要從JDK、maven、IDE等方方面面都要做相關設定,而且如果要做成前文那樣的docker鏡像,一行docker run命令就能開啟虛擬執行緒,還要在Dockerfile上做點事情(quarkus提供的基礎鏡像中沒有JDK19版本,另外啟動命令也要調整)

  • 上述這些都是本文的重點,欣宸已經將這些梳理清楚了,接下來咱們一起實戰吧,讓前文體驗過的web從無到有,再到順利運行,達到預期

  • 整個開發程序如下圖所示,一共十步,接下來開始動手

image-20221020081857985

開發環境

  • 開發電腦:MacBook Pro M1,macOS Monterey 12.6
  • IDE:IntelliJ IDEA 2022.3 EAP (Ultimate Edition) (即未發布前的早期預覽版)
  • 另外,M1芯片的電腦上開發和運行JDK19應用,與普通的X86相比感受不到任何變化,只有一點要注意:上傳docker鏡像到hub.docker.com時,鏡像的系統架構是ARM的,這樣的鏡像在X86電腦上下載下來后不能運行

下載JDK19

  • 下載jdk19,由于電腦是M1芯片,我選擇的jdk是azul版本,地址是:https://www.azul.com/downloads/?package=jdk#download-openjdk
  • 使用azul的jdk和之前的oracle版本并無區別,至少在開發環境感受不到,來看下azul官方的說法
image-20221015082121173
  • 實際上,azul的jdk很全面,x86芯片的各平臺版本安裝包都提供了,您可以根據自己電腦環境選擇下載,下面是我選擇的適合M1芯片的版本
image-20221015082450750
  • 下載完成后雙擊安裝即可

修改maven的配置

  • 我這里使用的是本地maven,其對應的JDK也要改成19,修改方法是調整環境變數JAVA_HOME,令其指向JDK19目錄(在我的電腦上,環境變數是在~/.zshrc里面)

image-20221015091138678

  • 修改后令環境變數生效,然后執行一下命令確認已經使用了JDK19
?  ~ mvn -version
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: /Users/zhaoqin/software/apache-maven-3.8.5
Java version: 19, vendor: Azul Systems, Inc., runtime: /Library/Java/JavaVirtualMachines/zulu-19.jdk/Contents/Home
Default locale: zh_CN_#Hans, platform encoding: UTF-8
OS name: "mac os x", version: "12.6", arch: "aarch64", family: "mac"

創建Quarkus專案

  • 打開IDEA,新建專案,選擇Quarkus專案
image-20221015083615179
  • 接下來選擇要用到的擴展包(其實就是在圖形化頁面添加jar依賴),這里的選擇如下圖:Reactive PostgreSQL clientRESTEasy Reactive Jackson
image-20221015084459075
  • 點擊上圖右下角的Create按鈕后專案開始創建,稍作等待,專案創建完成,如下圖,此刻只能感慨:quarkus太貼心,不但有demo原始碼,還有各種版本的Dockerfile檔案,而且git相關的配置也有,甚至README.md都寫得那么詳細,我是不是可以點擊運行按鈕直接把程式run起來了
image-20221015085440544

IDEA設定

  • 由于要用到JDK19,下面幾項設定需要檢查并確認
  • 首先是Project設定,如下圖

image-20221015112614328

  • 其次是Modules設定,先配置Sources這個tab頁

image-20221015112738859

  • 接下來是Dependencies這個tab頁
image-20221015112819900
  • 進入IDEA系統設定選單
image-20221015112115388
  • 如下圖,三個位置需要設定
image-20221015113055594
  • 設定完成了,接下來開始編碼

編碼

  • 首先確認pom.xml,這是IDEA幫我們創建的,內容如下,有兩處改動稍后會說到
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.bolingcavalry</groupId>
    <artifactId>quarkus-virual-threads-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <compiler-plugin.version>3.8.1</compiler-plugin.version>
        <maven.compiler.release>19</maven.compiler.release>
        <maven.compiler.source>19</maven.compiler.source>
        <maven.compiler.target>19</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>2.13.2.Final</quarkus.platform.version>
        <skipITs>true</skipITs>
        <surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-reactive-pg-client</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive</artifactId>
        </dependency>

        <!-- 生成測驗資料 -->
        <dependency>
            <groupId>net.datafaker</groupId>
            <artifactId>datafaker</artifactId>
            <version>1.6.0</version>
        </dependency>

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                        </goals>
                    </execution>
                </executions>
                <!-- 這里是新增的虛擬執行緒相關特性,start -->
                <configuration>
                    <source>19</source>
                    <target>19</target>
                    <compilerArgs>
                        <arg>--enable-preview</arg>
                    </compilerArgs>
                    <jvmArgs>--enable-preview --add-opens java.base/java.lang=ALL-UNNAMED</jvmArgs>
                </configuration>
                <!-- 這里是新增的虛擬執行緒相關特性,end -->
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                        <configuration>
                            <systemPropertyVariables>
                                <native.image.path>${project.build.directory}/${project.build.finalName}-runner
                                </native.image.path>
                                <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                                <maven.home>${maven.home}</maven.home>
                            </systemPropertyVariables>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <properties>
                <skipITs>false</skipITs>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>
</project>

  • pom.xml的第一處改動如下圖,要確保全部是19
image-20221020082700997
  • 第二處改動,是在quarkus-maven-plugin插件中增加額外的配置引數,如下圖紅框
image-20221020082849667
  • 接下來新增組態檔application.properties,在resources目錄下
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.max-size=8
quarkus.datasource.jdbc.min-size=2

quarkus.datasource.username=quarkus
quarkus.datasource.password=123456
quarkus.datasource.reactive.url=postgresql://192.168.0.1:5432/quarkus_test
  • 開始寫java代碼了,首先是啟動類VirtualThreadsDemoApp.java
package com.bolingcavalry;

import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.annotations.QuarkusMain;

@QuarkusMain
public class VirtualThreadsDemoApp {

    public static void main(String... args) {
        Quarkus.run(args);
    }
}
  • 資料庫對應的model類有兩個,第一個是gender欄位的列舉
package com.bolingcavalry.model;

public enum Gender {
    MALE, FEMALE;
}
  • 表對應的物體類
package com.bolingcavalry.model;

import io.vertx.mutiny.sqlclient.Row;

public class Person {
    private Long id;
    private String name;
    private int age;
    private Gender gender;
    private Integer externalId;

    public String getThreadInfo() {
        return threadInfo;
    }

    public void setThreadInfo(String threadInfo) {
        this.threadInfo = threadInfo;
    }

    private String threadInfo;

    public Person() {
    }

    public Person(Long id, String name, int age, Gender gender, Integer externalId) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.externalId = externalId;
        this.threadInfo = Thread.currentThread().toString();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public Integer getExternalId() {
        return externalId;
    }

    public void setExternalId(Integer externalId) {
        this.externalId = externalId;
    }

    public static Person from(Row row) {
        return new Person(
                row.getLong("id"),
                row.getString("name"),
                row.getInteger("age"),
                Gender.valueOf(row.getString("gender")),
                row.getInteger("external_id"));
    }
}
  • 接下來是操作資料庫的dao類,可見使用操作方式還是很原始的,還要在代碼中手寫SQL,取出也要逐個欄位匹配,其實quarkus也支持JPA,只不過本篇使用的是回應式資料庫驅動,所以選用的是Vert.x生成的連接池PgPool
package com.bolingcavalry.repository;

import com.bolingcavalry.model.Person;
import io.vertx.mutiny.pgclient.PgPool;
import io.vertx.mutiny.sqlclient.Row;
import io.vertx.mutiny.sqlclient.RowSet;
import io.vertx.mutiny.sqlclient.Tuple;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@ApplicationScoped
public class PersonRepositoryAsyncAwait {

    @Inject
    PgPool pgPool;

    public Person findById(Long id) {
        RowSet<Row> rowSet = pgPool
           .preparedQuery("SELECT id, name, age, gender, external_id FROM person WHERE id = $1")
           .executeAndAwait(Tuple.of(id));
        List<Person> persons = iterateAndCreate(rowSet);
        return persons.size() == 0 ? null : persons.get(0);
    }

    private List<Person> iterateAndCreate(RowSet<Row> rowSet) {
        List<Person> persons = new ArrayList<>();
        for (Row row : rowSet) {
            persons.add(Person.from(row));
        }
        return persons;
    }
}
  • 接下來就是前面截圖看到的web服務類VTPersonResource.java,它被注解@RunOnVirtualThread修飾,表示收到web請求在虛擬執行緒中執行回應代碼
package com.bolingcavalry.resource;

import com.bolingcavalry.model.Person;
import com.bolingcavalry.repository.PersonRepositoryAsyncAwait;
import io.smallrye.common.annotation.RunOnVirtualThread;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/vt/persons")
@RunOnVirtualThread
public class VTPersonResource {

    @Inject
    PersonRepositoryAsyncAwait personRepository;

    @GET
    @Path("/{id}")
    public Person getPersonById(@PathParam("id") Long id) {
        return personRepository.findById(id);
    }
}
  • 最后是用于對比的常規web服務類PoolPersonResource.java,這個就是中規中矩的在執行緒池中取一個執行緒來執行回應代碼
package com.bolingcavalry.resource;

import com.bolingcavalry.model.Person;
import com.bolingcavalry.repository.PersonRepositoryAsyncAwait;
import io.smallrye.common.annotation.RunOnVirtualThread;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/pool/persons")
public class PoolPersonResource {

    @Inject
    PersonRepositoryAsyncAwait personRepository;

    @GET
    @Path("/{id}")
    public Person getPersonById(@PathParam("id") Long id) {
        return personRepository.findById(id);
    }
}
  • 至此,編碼完成

IDEA啟動設定

  • 編碼完成后,在IDEA上啟動應用做本地除錯是咱們的基本操作,所以IDEA運行環境也要設定成支持JDK19的預覽特性
  • 打開入口類,點擊main方法前面的綠色箭頭,在彈出的選單上選擇Modify Run Configuration
image-20221015115712663
  • 在運行應用的設定頁面,如下操作

image-20221015115542673

  • 選中Add VM options
image-20221015115859652
  • 填入下圖箭頭所指的內容
image-20221015120024775
  • 終于,設定完成,接下來要啟動應用了

啟動和驗證

  • 啟動應用之前,請確認postgresql資料庫已啟動,并且資料已經匯入,具體啟動和匯入方法請參考前文
  • 點擊下圖紅色箭頭中指向的按鈕,即可在IDEA中運行應用
image-20221021081112061
  • 瀏覽器訪問地址:http://localhost:8080/vt/persons/1 ,如下圖,符合預期
image-20221021082603972
  • 在前文中,咱們是在docker上運行應用的,另外在實際場景中應用運行在docker或者k8s環境也是普遍情況,所以接下來一起實戰將用做成docker鏡像并驗證

構建鏡像

  • 在創建工程的時候,IDEA就用quarkus模板自動創建了多個Dockerfile檔案,下圖紅框中全是
image-20221021083348600
  • 如果當前應用的JDK不是19,而是11或者17,那么上圖紅框中的Dockerfile檔案就能直接使用了,然而,由于今天咱們應用的JDK必須是19,就無法使用這些Dockerfile了,必須自己寫一個,原因很簡單,打開Dockerfile.jvm,如下圖紅色箭頭所示,基礎鏡像是jdk17,而這個倉庫中并沒有JDK19,也就是說quarkus還沒有發布JDK19版本的基礎鏡像,咱們要自己找一個,另外,容器啟動命令也要調整,需要加入--enable-preview才能開啟JVM的虛擬執行緒
image-20221021083635218
  • 自己寫的Dockerile檔案名為Dockerfile.19,內容如下,可見非常簡單:先換基礎鏡像,再把mvn構建結果復制過去,最后加個啟動命令就完事兒了(遠不如官方的分層構建節省空間,然而在官方的JDK19鏡像方案出來之前,先用下面這個將就著用吧)
FROM openjdk:19

ENV LANGUAGE='en_US:en'

# 執行作業目錄
WORKDIR application

COPY --chown=185 target/*.jar ./

RUN mkdir config

EXPOSE 8080
USER 185
ENTRYPOINT ["java", "-jar", "--enable-preview", "quarkus-virual-threads-demo-1.0-SNAPSHOT-runner.jar"]
  • 接下來可以制作鏡像了,請確保自己電腦上docker已在運行

  • 首先是常規maven編譯打包(uber-jar表示生成的jar中包含了所有依賴庫)

mvn clean package -U -DskipTests -Dquarkus.package.type=uber-jar
  • 構建docker鏡像
docker build -f src/main/docker/Dockerfile.19 -t bolingcavalry/quarkus-virual-threads-demo:0.0.2 .
  • 鏡像制作成功,控制臺輸出如下圖
image-20221022072718957
  • 如果您有hub.docker.com的賬號,也可以像我一樣推送到公共倉庫,方便大家使用

例外測驗(沒有enable-preview引數會怎么樣?)

  • 回顧Dockerfile中啟動應用的命令,由于虛擬執行緒是JDK19的預覽功能,因此必須添加下圖紅色箭頭所指的--enable-preview引數才能讓虛擬執行緒功能生效
image-20221022073455393
  • 于是我就在想:不加這個引數會咋樣?也就是不開啟虛擬執行緒,但是代碼中卻要用它,那么真正運行的時候會如何呢?
  • 瞎猜是沒用的,還是試試吧,在啟動引數中洗掉--enable-preview,如下圖,再重新構建鏡像
image-20221022074847459
  • 像前文那樣運行容器(再次提醒,確保資料庫是正常的),再在瀏覽器訪問http://localhost:8080/vt/persons/1,頁面正常顯示了,看來功能是不受影響的
image-20221022082633379
  • 再用docker logs命令查看后臺日志,如下圖箭頭所示,quarkus給出了WARN級別的提示:由于當前虛擬機不支持虛擬執行緒,改為使用默認的阻塞來執行業務邏輯
image-20221022075007690
  • 小結:在不支持虛擬執行緒的環境強行使用虛擬執行緒,quarkus會選擇兼容的方式繼續完成任務

小結和展望

  • 至此,一個完整的quarkus應用已開發完成,該應用使用虛擬執行緒來回應web請求,而且在quarkus官方還沒有提供方案的前提下,咱們依舊完成了docker鏡像的制作,最后,因為好奇,還關閉重要引數嘗試了一下,一系列操作下來,相信您已經對基礎開發了如指掌了

  • 最后,還剩下兩個遺留問題,相信您也會有類似困惑

    1. 虛擬執行緒和常規子執行緒的區別,究竟能不能看出來?前文已經驗證了性能上區別不大,那還有別的方式來觀察和區分嗎?
    2. 能不能稍微深入一點,僅憑一個@RunOnVirtualThread注解就強行寫了兩篇博客,實在是太忽悠人了
  • 以上問題會在接下來的《支持JDK19虛擬執行緒的web框架,終篇》得到解決,還是那句熟悉的廣告詞:欣宸原創,不辜負您的期待

歡迎關注博客園:程式員欣宸

學習路上,你不孤單,欣宸原創一路相伴...

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

標籤:其他

上一篇:【HDLBits刷題筆記】12 More Circuits

下一篇:深入理解 virtual 關鍵字

標籤雲
其他(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