搜尋
首頁後端開發Golang使用 Go、PostgreSQL、Google Cloud 和 CockroachDB 建立 API

我使用 Go 和 PostgreSQL 建立了一個 API,使用 Google Cloud Run、Cloud Build、Secret Manager 和 ArtifactRegistry 設定了 CI/CD 管道,並將 Cloud Run 實例連接到 CockroachDB。

此API基於遊戲《核心危機:最終幻想VII》,模擬「物質融合」。本文的目標受眾是只想了解如何建置和部署 API 的開發人員。我還有另一篇文章,其中討論了我在從事該專案時學到的所有內容、哪些內容不起作用,以及理解和翻譯遊戲的材質融合規則(連結即將推出)。

方便參考的鏈接

  • GitHub 儲存庫與自述文件
  • Swagger (OpenAPI) 文件與測驗
  • 公共郵差收藏
  • 領域模型來源

API目標

3 個端點 - 健康檢查 (GET)、所有材料清單 (GET) 和模擬材料融合 (POST)

領域模型

物質(單數和複數)是一個水晶球,作為魔法的來源。遊戲中有 144 種不同的材質,大致分為 4 類:「魔法」、「指令」、「支援」和「獨立」。然而,為了弄清楚物質融合的規則,根據它們的融合行為,更容易有32個內部類別,以及這些類別內的8個等級(參見參考資料) .

一種材料在使用一定時間後就會變得「精通」。持續時間在這裡並不重要。

最重要的是,兩種材質可以融合產生一種新材質。融合規則受以下因素影響:

  • 是否掌握其中一種或兩種材料。
  • 哪一種材料先出現(如 X Y 不一定等於 Y X)。
  • 材質內部類別。
  • 材質等級。

Building an API with Go, PostgreSQL, Google Cloud and CockroachDB

並且有許多例外,其中一些規則具有 3 層嵌套的 if-else 邏輯。這消除了在資料庫中建立一個簡單表格並將 1000 條規則儲存到其中的可能性,或想出一個公式來規則所有規則的可能性。

簡而言之,我們需要:

  1. 一個表材質,其中包含列name(string)、materia_type(ENUM)(32 個內部類別)、grade(integer)、display_materia_type(ENUM)(遊戲中使用的4 個類別)、description(string) 和id(整數)作為自增主鍵。
  2. 封裝基本規則格式MateriaTypeA MateriaTypeB = MateriaTypeC的資料結構。
  3. 使用基本和複雜規則來決定輸出材料的內部類別和等級的代碼。

1. 設定本機 PostgreSQL 資料庫

理想情況下,您可以從網站本身安裝資料庫。但是pgAdmin工具因為某些原因無法連接到DB,所以我使用了Homebrew。

安裝

brew install postgresql@17

這將安裝一大堆 CLI 二進位檔案以幫助使用資料庫。

可選:將 /opt/homebrew/opt/postgresql@17/bin 加入 $PATH 變數。

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

建立使用者和權限

-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

建立表

CREATE TYPE display_materia_type AS ENUM ('Magic', 'Command', 'Support', 'Independent');

CREATE TYPE materia_type AS ENUM ('Fire', 'Ice', 'Lightning', 'Restore', 'Full Cure', 'Status Defense', 'Defense', 'Absorb Magic', 'Status Magic', 'Fire & Status', 'Ice & Status', 'Lightning & Status', 'Gravity', 'Ultimate', 'Quick Attack', 'Quick Attack & Status', 'Blade Arts', 'Blade Arts & Status', 'Fire Blade', 'Ice Blade', 'Lightning Blade', 'Absorb Blade', 'Item', 'Punch', 'SP Turbo', 'HP Up', 'AP Up', 'ATK Up', 'VIT Up', 'MAG Up', 'SPR Up', 'Dash', 'Dualcast', 'DMW', 'Libra', 'MP Up', 'Anything');

CREATE TABLE materia (
    id integer NOT NULL,
    name character varying(50) NOT NULL,
    materia_type materia_type NOT NULL,
    grade integer NOT NULL,
    display_materia_type display_materia_type,
    description text
    CONSTRAINT materia_pkey PRIMARY KEY (id)
);

-- The primary key 'id' should auto-increment by 1 for every row entry.
CREATE SEQUENCE materia_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE materia_id_seq OWNED BY materia.id;

ALTER TABLE ONLY materia ALTER COLUMN id SET DEFAULT nextval('materia_id_seq'::REGCLASS);

新增數據

建立包含表頭和資料的 Excel 工作表,並將其匯出為 CSV 檔案。然後運行命令:

COPY materia(name,materia_type,grade,display_materia_type,description) FROM
 '<path_to_csv_file>/materiadata.csv' DELIMITER ',' CSV HEADER;
</path_to_csv_file>

2. 建立Go伺服器

使用 autostrada.dev 建立樣板程式碼。新增 api、postgresql、httprouter、env var config、tintedlogging、git、live reload、makefile 的選項。我們最後得到這樣的文件結構:

? codebase
├─ cmd
│  └─ api
│     ├─ errors.go
│     ├─ handlers.go
│     ├─ helpers.go
│     ├─ main.go
│     ├─ middleware.go
│     └─ server.go
├─ internal
│  ├─ database --- db.go
│  ├─ env --- env.go
│  ├─ request --- json.go
│  ├─ response --- json.go
│  └─ validator
│     ├─ helpers.go
│     └─ validators.go
├─ go.mod
├─ LICENSE
├─ Makefile
├─ README.md
└─ README.html

.env 文件

樣板產生器已建立程式碼來取得環境變數並將它們新增至程式碼中,但我們可以更輕鬆地追蹤和更新值。

建立 /.env 檔案。新增以下值:

HTTP_PORT=4444
DB_DSN=go_client:<password>@localhost:5432/materiafusiondb?sslmode=disable
API_TIMEOUT_SECONDS=5
API_CALLS_ALLOWED_PER_SECOND=1
</password>

新增 godotenv 庫:

go get github.com/joho/godotenv

將以下內容加入 main.go:

// At the beginning of main():
err := godotenv.Load(".env") // Loads environment variables from .env file
if err != nil { // This will be true in prod, but that's fine.
  fmt.Println("Error loading .env file")
}


// Modify config struct:
type config struct {
  baseURL string
  db      struct {
    dsn string
  }
  httpPort                 int
  apiTimeout               int
  apiCallsAllowedPerSecond float64
}

// Modify run() to use the new values from .env:
cfg.httpPort = env.GetInt("HTTP_PORT")
cfg.db.dsn = env.GetString("DB_DSN")
cfg.apiTimeout = env.GetInt("API_TIMEOUT_SECONDS")
cfg.apiCallsAllowedPerSecond = float64(env.GetInt("API_CALLS_ALLOWED_PER_SECOND"))

// cfg.baseURL = env.GetString("BASE_URL") - not required

中介軟體和路由

樣板已經有一個中間件可以從恐慌中恢復。我們將新增另外 3 個:Content-Type 檢查、速率限制和 API 逾時保護。

新增收費站庫:

go get github.com/didip/tollbooth

更新

func (app *application) contentTypeCheck(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  if r.Header.Get("Content-Type") != "application/json" {
   app.unsupportedMediaType(w, r)

   return
  }
  next.ServeHTTP(w, r)
 })
}


func (app *application) rateLimiter(next http.Handler) http.Handler {
 limiter := tollbooth.NewLimiter(app.config.apiCallsAllowedPerSecond, nil)
 limiter.SetIPLookups([]string{"X-Real-IP", "X-Forwarded-For", "RemoteAddr"})

 return tollbooth.LimitHandler(limiter, next)
}


func (app *application) apiTimeout(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  timeoutDuration := time.Duration(app.config.apiTimeout) * time.Second

  ctx, cancel := context.WithTimeout(r.Context(), timeoutDuration)
  defer cancel()

  r = r.WithContext(ctx)

  done := make(chan struct{})

  go func() {
   next.ServeHTTP(w, r)
   close(done)
  }()

  select {
  case 



<p>中間件需要加入到路由中。它們可以添加到所有路由,也可以添加到特定路由。在我們的範例中,僅 POST 請求需要 Content-Type 檢查(即強制輸入標頭包含 Content-Type: application/json)。所以修改routes.go如下:<br>
</p>

<pre class="brush:php;toolbar:false">func (app *application) routes() http.Handler {
 mux := httprouter.New()

 mux.NotFound = http.HandlerFunc(app.notFound)
 mux.MethodNotAllowed = http.HandlerFunc(app.methodNotAllowed)

 // Serve the Swagger UI. Uncomment this line later
 // mux.Handler("GET", "/docs/*any", httpSwagger.WrapHandler)

 mux.HandlerFunc("GET", "/status", app.status)
 mux.HandlerFunc("GET", "/materia", app.getAllMateria)

 // Adding content-type check middleware to only the POST method
 mux.Handler("POST", "/fusion", app.contentTypeCheck(http.HandlerFunc(app.fuseMateria)))

 return app.chainMiddlewares(mux)
}

func (app *application) chainMiddlewares(next http.Handler) http.Handler {
 middlewares := []func(http.Handler) http.Handler{
  app.recoverPanic,
  app.apiTimeout,
  app.rateLimiter,
 }

 for _, middleware := range middlewares {
  next = middleware(next)
 }

 return next
}

錯誤處理

/api/errors.go 中加入以下方法來幫助中間件功能:

func (app *application) unsupportedMediaType(w http.ResponseWriter, r *http.Request) {
 message := fmt.Sprintf("The %s Content-Type is not supported", r.Header.Get("Content-Type"))
 app.errorMessage(w, r, http.StatusUnsupportedMediaType, message, nil)
}

func (app *application) gatewayTimeout(w http.ResponseWriter, r *http.Request) {
 message := "Request timed out"
 app.errorMessage(w, r, http.StatusGatewayTimeout, message, nil)
}

請求和響應結構文件

/api/dtos.go :

package main

// MateriaDTO provides Materia details - Name, Description and Type (Magic / Command / Support / Independent)
type MateriaDTO struct {
 Name        string `json:"name" example:"Thunder"`
 Type        string `json:"type" example:"Magic"`
 Description string `json:"description" example:"Shoots lightning forward dealing thunder damage."`
}

// StatusDTO provides status of the server
type StatusDTO struct {
 Status string `json:"Status" example:"OK"`
}

// ErrorResponseDTO provides Error message
type ErrorResponseDTO struct {
 Error string `json:"Error" example:"The server encountered a problem and could not process your request"`
}

/api/requests.go :

brew install postgresql@17

產生程式碼中的驗證器稍後將用於驗證融合端點的輸入欄位。

組合規則的資料結構

建立檔案 /internal/crisis-core-materia-fusion/constants.go

加入以下內容:

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

32 種 MateriaType 的完整清單可以在此處找到。

建立檔案 /internal/crisis-core-materia-fusion/models.go

加入以下內容:

-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

完整的規則清單可以在這裡找到。

api/handlers.go 中材質的處理程序

CREATE TYPE display_materia_type AS ENUM ('Magic', 'Command', 'Support', 'Independent');

CREATE TYPE materia_type AS ENUM ('Fire', 'Ice', 'Lightning', 'Restore', 'Full Cure', 'Status Defense', 'Defense', 'Absorb Magic', 'Status Magic', 'Fire & Status', 'Ice & Status', 'Lightning & Status', 'Gravity', 'Ultimate', 'Quick Attack', 'Quick Attack & Status', 'Blade Arts', 'Blade Arts & Status', 'Fire Blade', 'Ice Blade', 'Lightning Blade', 'Absorb Blade', 'Item', 'Punch', 'SP Turbo', 'HP Up', 'AP Up', 'ATK Up', 'VIT Up', 'MAG Up', 'SPR Up', 'Dash', 'Dualcast', 'DMW', 'Libra', 'MP Up', 'Anything');

CREATE TABLE materia (
    id integer NOT NULL,
    name character varying(50) NOT NULL,
    materia_type materia_type NOT NULL,
    grade integer NOT NULL,
    display_materia_type display_materia_type,
    description text
    CONSTRAINT materia_pkey PRIMARY KEY (id)
);

-- The primary key 'id' should auto-increment by 1 for every row entry.
CREATE SEQUENCE materia_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE materia_id_seq OWNED BY materia.id;

ALTER TABLE ONLY materia ALTER COLUMN id SET DEFAULT nextval('materia_id_seq'::REGCLASS);

伺服器內緩存

我們使用伺服器內緩存,因為:

  1. 從資料庫取得的資料永遠不會改變。
  2. 材質和融合端點使用相同的資料。

更新main.go:

COPY materia(name,materia_type,grade,display_materia_type,description) FROM
 '<path_to_csv_file>/materiadata.csv' DELIMITER ',' CSV HEADER;
</path_to_csv_file>

更新 api/helpers.go:

? codebase
├─ cmd
│  └─ api
│     ├─ errors.go
│     ├─ handlers.go
│     ├─ helpers.go
│     ├─ main.go
│     ├─ middleware.go
│     └─ server.go
├─ internal
│  ├─ database --- db.go
│  ├─ env --- env.go
│  ├─ request --- json.go
│  ├─ response --- json.go
│  └─ validator
│     ├─ helpers.go
│     └─ validators.go
├─ go.mod
├─ LICENSE
├─ Makefile
├─ README.md
└─ README.html

api/handlers.go 中的融合處理程序

HTTP_PORT=4444
DB_DSN=go_client:<password>@localhost:5432/materiafusiondb?sslmode=disable
API_TIMEOUT_SECONDS=5
API_CALLS_ALLOWED_PER_SECOND=1
</password>

完整的處理程序程式碼可以在這裡找到。

Swagger UI 和 OpenAPI 定義文檔

新增 Swagger 庫:

go get github.com/joho/godotenv

在routes.go中取消註解Swagger行,並新增導入:

// At the beginning of main():
err := godotenv.Load(".env") // Loads environment variables from .env file
if err != nil { // This will be true in prod, but that's fine.
  fmt.Println("Error loading .env file")
}


// Modify config struct:
type config struct {
  baseURL string
  db      struct {
    dsn string
  }
  httpPort                 int
  apiTimeout               int
  apiCallsAllowedPerSecond float64
}

// Modify run() to use the new values from .env:
cfg.httpPort = env.GetInt("HTTP_PORT")
cfg.db.dsn = env.GetString("DB_DSN")
cfg.apiTimeout = env.GetInt("API_TIMEOUT_SECONDS")
cfg.apiCallsAllowedPerSecond = float64(env.GetInt("API_CALLS_ALLOWED_PER_SECOND"))

// cfg.baseURL = env.GetString("BASE_URL") - not required

在處理程序、DTO 和模型檔案中,新增 Swagger 文件的註解。請參閱此以了解所有選項。

在終端機中,運作:

go get github.com/didip/tollbooth

這將建立一個 api/docs 資料夾,其中包含可用於 Go、JSON 和 YAML 的定義。

要測試它,請啟動本機伺服器並開啟 http://localhost:4444/docs。


最終資料夾結構:

func (app *application) contentTypeCheck(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  if r.Header.Get("Content-Type") != "application/json" {
   app.unsupportedMediaType(w, r)

   return
  }
  next.ServeHTTP(w, r)
 })
}


func (app *application) rateLimiter(next http.Handler) http.Handler {
 limiter := tollbooth.NewLimiter(app.config.apiCallsAllowedPerSecond, nil)
 limiter.SetIPLookups([]string{"X-Real-IP", "X-Forwarded-For", "RemoteAddr"})

 return tollbooth.LimitHandler(limiter, next)
}


func (app *application) apiTimeout(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  timeoutDuration := time.Duration(app.config.apiTimeout) * time.Second

  ctx, cancel := context.WithTimeout(r.Context(), timeoutDuration)
  defer cancel()

  r = r.WithContext(ctx)

  done := make(chan struct{})

  go func() {
   next.ServeHTTP(w, r)
   close(done)
  }()

  select {
  case 



<h2>
  
  
  3. 在 CockroachDB 中設定遠端 PostgreSQL 實例
</h2>

<ol>
<li>使用此處的步驟。 </li>
<li>建立憑證後,在專案中建立 <rootfolder>/certs/root.crt 並在其中新增憑證。我們稍後將在 Google Run 配置中引用此文件。 </rootfolder>
</li>
<li>
<strong>警告! </strong>我們<strong>不</strong>將此資料夾推送到遠端儲存庫。將 certs/ 資料夾新增至 .gitignore。如果您願意,我們在本地創建證書只是為了測試連接。 </li>
<li>現在,當您前往 CockroachDB → 儀表板 → 左側選單 → 資料庫時,您應該可以看到您建立的資料庫。 </li>
</ol>

<h3>
  
  
  遷移
</h3>

<p>從本機資料庫執行個體中,執行:<br>
</p><pre class="brush:php;toolbar:false">brew install postgresql@17
  1. 到 CockroachDB → 左側選單 → 遷移 → 新增架構 → 拖曳剛剛取得的 SQL 檔案。除表資料插入之外的所有步驟都將運行。它還會向您顯示已執行的步驟清單。
  2. 在撰寫本文時,CockroachDB 中的 PostgreSQL 實例不支援 IMPORT INTO 等語句。因此,我必須在本機 SQL 檔案中建立 270 行的 INSERT 語句(我們可以從剛剛獲得的 pg_dump 輸出得出)。
  3. 登入遠端實例,並執行SQL檔案。

登入遠端實例:

# create the DB
createdb materiafusiondb
# step into the DB to perform SQL commands
psql materiafusiondb

4. 部署 Google Cloud Run 實例

  1. 像這樣建立一個 Dockerfile。
  2. 前往 Google Cloud Run 並為 API 建立一個新專案。
  3. 建立服務→ 從儲存庫持續部署使用雲端建置進行設定儲存庫提供者 = Github → 選擇您的儲存庫→ 建置類型 = Dockerfile → 儲存。
  4. 驗證 = 允許未經授權的呼叫
  5. 大多數預設值應該就可以了。
  6. 向下捲動至貨櫃 → 貨櫃港口 = 4444。
  7. 選擇變數和秘密選項卡,然後加入與本地 .env 檔案相同的環境變數。

價值觀:

  1. HTTP_PORT = 4444
  2. DB_DSN = ?sslmode=verify-full&sslrootcert=/app/certs/root.crt
  3. API_TIMEOUT_SECONDS = 5
  4. API_CALLS_ALLOWED_PER_SECOND = 1

使用 Google Secret Manager 取得證書

最後一塊拼圖。

  1. 搜尋 Secret Manager → 建立 Secret → Name = ‘DB_CERT’ → 上傳 CockroachDB 的 .crt 憑證。
  2. 在 Cloud Run →(您的服務)→ 點選 編輯持續部署 → 向下捲動至設定 → 開啟編輯器。
  3. 將此新增為第一步:
-- create an SQL user to be used by the Go server
CREATE USER go_client WITH PASSWORD 'xxxxxxxx';

-- The Go server doesn't ever need to add data to the DB. 
-- So let's give it just read permission.
CREATE ROLE readonly_role;
GRANT USAGE ON SCHEMA public TO readonly_role;

-- This command gives SELECT access to all future created tables. 
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_role;

-- If you want to be more strict and give access only to tables that already exist, use this:
-- GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_role;

GRANT readonly_role TO go_client;

這將使 Cloud Build 在建置開始之前在我們的專案中建立檔案 certs/root.crt,以便 Dockerfile 可以存取它,即使我們從未將其推送到我們的 Github 儲存庫。


就是這樣。嘗試推送提交並檢查建置是否觸發。 Cloud Run 儀表板將顯示您所託管的 Go 伺服器的 URL。


有關「為什麼你做了 X 而不是 Y?」的問題讀這個。

對於您想了解或討論的任何其他內容,請訪問此處,或在下面發表評論。

以上是使用 Go、PostgreSQL、Google Cloud 和 CockroachDB 建立 API的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Golang vs. Python:利弊Golang vs. Python:利弊Apr 21, 2025 am 12:17 AM

Golangisidealforbuildingscalablesystemsduetoitsefficiencyandconcurrency,whilePythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.Golang'sdesignencouragesclean,readablecodeanditsgoroutinesenableefficientconcurrentoperations,t

Golang和C:並發與原始速度Golang和C:並發與原始速度Apr 21, 2025 am 12:16 AM

Golang在並發性上優於C ,而C 在原始速度上優於Golang。 1)Golang通過goroutine和channel實現高效並發,適合處理大量並發任務。 2)C 通過編譯器優化和標準庫,提供接近硬件的高性能,適合需要極致優化的應用。

為什麼要使用Golang?解釋的好處和優勢為什麼要使用Golang?解釋的好處和優勢Apr 21, 2025 am 12:15 AM

選擇Golang的原因包括:1)高並發性能,2)靜態類型系統,3)垃圾回收機制,4)豐富的標準庫和生態系統,這些特性使其成為開發高效、可靠軟件的理想選擇。

Golang vs.C:性能和速度比較Golang vs.C:性能和速度比較Apr 21, 2025 am 12:13 AM

Golang適合快速開發和並發場景,C 適用於需要極致性能和低級控制的場景。 1)Golang通過垃圾回收和並發機制提升性能,適合高並發Web服務開發。 2)C 通過手動內存管理和編譯器優化達到極致性能,適用於嵌入式系統開發。

golang比C快嗎?探索極限golang比C快嗎?探索極限Apr 20, 2025 am 12:19 AM

Golang在編譯時間和並發處理上表現更好,而C 在運行速度和內存管理上更具優勢。 1.Golang編譯速度快,適合快速開發。 2.C 運行速度快,適合性能關鍵應用。 3.Golang並發處理簡單高效,適用於並發編程。 4.C 手動內存管理提供更高性能,但增加開發複雜度。

Golang:從Web服務到系統編程Golang:從Web服務到系統編程Apr 20, 2025 am 12:18 AM

Golang在Web服務和系統編程中的應用主要體現在其簡潔、高效和並發性上。 1)在Web服務中,Golang通過強大的HTTP庫和並發處理能力,支持創建高性能的Web應用和API。 2)在系統編程中,Golang利用接近硬件的特性和對C語言的兼容性,適用於操作系統開發和嵌入式系統。

Golang vs.C:基準和現實世界的表演Golang vs.C:基準和現實世界的表演Apr 20, 2025 am 12:18 AM

Golang和C 在性能對比中各有優劣:1.Golang適合高並發和快速開發,但垃圾回收可能影響性能;2.C 提供更高性能和硬件控制,但開發複雜度高。選擇時需綜合考慮項目需求和團隊技能。

Golang vs. Python:比較分析Golang vs. Python:比較分析Apr 20, 2025 am 12:17 AM

Golang适合高性能和并发编程场景,Python适合快速开发和数据处理。1.Golang强调简洁和高效,适用于后端服务和微服务。2.Python以简洁语法和丰富库著称,适用于数据科学和机器学习。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用