通过实际项目案例学习 Zig 编程,对比 Go 实现方式
创建一个简单的 HTTP 服务器,展示 Zig 和 Go 在网络编程方面的差异。 这个示例将演示两种语言的并发模型、错误处理和性能特征。
const std = @import("std");
const net = std.net;
const Thread = std.Thread;
const Server = struct {
listener: net.StreamServer,
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) !Server {
var server = net.StreamServer.init(.{});
return Server{
.listener = server,
.allocator = allocator,
};
}
pub fn deinit(self: *Server) void {
self.listener.deinit();
}
pub fn start(self: *Server, port: u16) !void {
const address = try net.Address.parseIp("127.0.0.1", port);
try self.listener.listen(address);
std.debug.print("Server listening on http://127.0.0.1:{}\n", .{port});
while (true) {
const connection = try self.listener.accept();
// 为每个连接创建新线程
const thread = try Thread.spawn(.{}, handleConnection, .{
connection,
self.allocator,
});
thread.detach();
}
}
};
fn handleConnection(connection: net.StreamServer.Connection, allocator: std.mem.Allocator) !void {
defer connection.stream.close();
var buffer: [1024]u8 = undefined;
const bytes_read = try connection.stream.read(&buffer);
if (bytes_read == 0) return;
const request = buffer[0..bytes_read];
// 简单的 HTTP 响应
const response = \\\ "HTTP/1.1 200 OK\\r\\n" \\\ "Content-Type: text/html\\r\\n" \\\ "Content-Length: 100\\r\\n" \\\ "\\r\\n" \\\ "Hello from Zig HTTP Server!
" \\\ "Current time: {d}
";
var response_buffer: [512]u8 = undefined;
const current_time = std.time.timestamp();
const formatted_response = try std.fmt.bufPrint(
&response_buffer,
response,
.{current_time}
);
_ = try connection.stream.write(formatted_response);
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var server = try Server.init(gpa.allocator());
defer server.deinit();
try server.start(8080);
}
package main
import (
"fmt"
"log"
"net/http"
"time"
)
type Server struct {
mux *http.ServeMux
}
func NewServer() *Server {
s := &Server{
mux: http.NewServeMux(),
}
s.mux.HandleFunc("/", s.handleRoot)
return s
}
func (s *Server) handleRoot(w http.ResponseWriter, r *http.Request) {
currentTime := time.Now().Unix()
response := fmt.Sprintf(`
Hello from Go HTTP Server!
Current time: %d
Request path: %s
`, currentTime, r.URL.Path)
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(response))
}
func (s *Server) Start(port string) error {
log.Printf("Server listening on http://localhost%s\n", port)
return http.ListenAndServe(port, s.mux)
}
func main() {
server := NewServer()
if err := server.Start(":8080"); err != nil {
log.Fatal("Server failed to start:", err)
}
}
处理 CSV 文件,统计数据的平均值和标准差。展示两种语言在文件处理和数据分析方面的不同方法。
const std = @import("std");
const DataStats = struct {
count: usize,
sum: f64,
mean: f64,
stddev: f64,
min: f64,
max: f64,
};
const CSVProcessor = struct {
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) CSVProcessor {
return CSVProcessor{ .allocator = allocator };
}
pub fn processFile(self: *CSVProcessor, filename: []const u8) !DataStats {
const file = try std.fs.cwd().openFile(filename, .{});
defer file.close();
const stat = try file.stat();
const content = try file.readToEndAlloc(self.allocator, stat.size);
defer self.allocator.free(content);
var values = std.ArrayList(f64).init(self.allocator);
defer values.deinit();
var lines = std.mem.tokenize(u8, content, "\\n");
while (lines.next()) |line| {
if (line.len == 0) continue;
var fields = std.mem.tokenize(u8, line, ",");
while (fields.next()) |field| {
const trimmed = std.mem.trim(u8, field, " \\t");
if (trimmed.len > 0) {
const value = try std.fmt.parseFloat(f64, trimmed);
try values.append(value);
}
}
}
return self.calculateStats(values.items);
}
fn calculateStats(self: *CSVProcessor, values: []f64) DataStats {
if (values.len == 0) {
return DataStats{
.count = 0,
.sum = 0,
.mean = 0,
.stddev = 0,
.min = 0,
.max = 0,
};
}
var sum: f64 = 0;
var min: f64 = values[0];
var max: f64 = values[0];
for (values) |value| {
sum += value;
if (value < min) min = value;
if (value > max) max = value;
}
const mean = sum / @as(f64, @floatFromInt(values.len));
var variance: f64 = 0;
for (values) |value| {
const diff = value - mean;
variance += diff * diff;
}
variance /= @as(f64, @floatFromInt(values.len));
const stddev = @sqrt(variance);
return DataStats{
.count = values.len,
.sum = sum,
.mean = mean,
.stddev = stddev,
.min = min,
.max = max,
};
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// 创建示例 CSV 文件
const sample_data =
\\Value1,Value2,Value3\\n" \\\ "10.5,20.3,15.7\\n" \\\ "25.1,30.2,18.9\\n" \\\ "35.8,40.1,22.4\\n" \\\ "45.2,50.3,28.7\\n";
const file = try std.fs.cwd().createFile("sample.csv", .{});
try file.writeAll(sample_data);
file.close();
var processor = CSVProcessor.init(allocator);
const stats = try processor.processFile("sample.csv");
std.debug.print("=== CSV 文件统计结果 ===\\n", .{});
std.debug.print("数据点数量: {}\\n", .{stats.count});
std.debug.print("总和: {d:.2}\\n", .{stats.sum});
std.debug.print("平均值: {d:.2}\\n", .{stats.mean});
std.debug.print("标准差: {d:.2}\\n", .{stats.stddev});
std.debug.print("最小值: {d:.2}\\n", .{stats.min});
std.debug.print("最大值: {d:.2}\\n", .{stats.max});
// 清理文件
try std.fs.cwd().deleteFile("sample.csv");
}
package main
import (
"encoding/csv"
"fmt"
"math"
"os"
"strconv"
)
type DataStats struct {
Count int
Sum float64
Mean float64
StdDev float64
Min float64
Max float64
}
type CSVProcessor struct{}
func NewCSVProcessor() *CSVProcessor {
return &CSVProcessor{}
}
func (p *CSVProcessor) ProcessFile(filename string) (*DataStats, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
var values []float64
for _, record := range records {
for _, field := range record {
if value, err := strconv.ParseFloat(field, 64); err == nil {
values = append(values, value)
}
}
}
return p.calculateStats(values), nil
}
func (p *CSVProcessor) calculateStats(values []float64) *DataStats {
if len(values) == 0 {
return &DataStats{}
}
sum := 0.0
min := values[0]
max := values[0]
for _, value := range values {
sum += value
if value < min {
min = value
}
if value > max {
max = value
}
}
mean := sum / float64(len(values))
variance := 0.0
for _, value := range values {
diff := value - mean
variance += diff * diff
}
variance /= float64(len(values))
stddev := math.Sqrt(variance)
return &DataStats{
Count: len(values),
Sum: sum,
Mean: mean,
StdDev: stddev,
Min: min,
Max: max,
}
}
func main() {
// 创建示例 CSV 文件
sampleData := `Value1,Value2,Value3
10.5,20.3,15.7
25.1,30.2,18.9
35.8,40.1,22.4
45.2,50.3,28.7`
err := os.WriteFile("sample.csv", []byte(sampleData), 0644)
if err != nil {
panic(err)
}
processor := NewCSVProcessor()
stats, err := processor.ProcessFile("sample.csv")
if err != nil {
panic(err)
}
fmt.Println("=== CSV 文件统计结果 ===")
fmt.Printf("数据点数量: %d\n", stats.Count)
fmt.Printf("总和: %.2f\n", stats.Sum)
fmt.Printf("平均值: %.2f\n", stats.Mean)
fmt.Printf("标准差: %.2f\n", stats.StdDev)
fmt.Printf("最小值: %.2f\n", stats.Min)
fmt.Printf("最大值: %.2f\n", stats.Max)
// 清理文件
os.Remove("sample.csv")
}
实现一个线程安全的计数器,演示两种语言的并发模型和同步机制。 这个示例将展示 goroutines vs 线程、channels vs 锁的对比。
const std = @import("std");
const Thread = std.Thread;
const Mutex = Thread.Mutex;
const Counter = struct {
value: i64,
mutex: Mutex,
pub fn init() Counter {
return Counter{
.value = 0,
.mutex = Mutex{},
};
}
pub fn increment(self: *Counter, amount: i64) void {
self.mutex.lock();
defer self.mutex.unlock();
self.value += amount;
}
pub fn get(self: *Counter) i64 {
self.mutex.lock();
defer self.mutex.unlock();
return self.value;
}
};
const ThreadData = struct {
counter: *Counter,
iterations: usize,
thread_id: usize,
};
fn workerThread(data: *ThreadData) void {
var i: usize = 0;
while (i < data.iterations) : (i += 1) {
data.counter.increment(1);
// 模拟一些工作
if (i % 1000 == 0) {
std.time.sleep(1); // 1 纳秒
}
}
std.debug.print("Thread {} completed {} iterations\n", .{
data.thread_id, data.iterations
});
}
pub fn main() !void {
const num_threads = 4;
const iterations_per_thread = 10000;
var counter = Counter.init();
std.debug.print("Starting concurrent counter test...\n", .{});
std.debug.print("Threads: {}, Iterations per thread: {}\n", .{
num_threads, iterations_per_thread
});
var threads: [num_threads]Thread = undefined;
var thread_data: [num_threads]ThreadData = undefined;
// 启动所有线程
for (&threads, &thread_data, 0..) |*thread, *data, i| {
data.* = ThreadData{
.counter = &counter,
.iterations = iterations_per_thread,
.thread_id = i,
};
thread.* = try Thread.spawn(.{}, workerThread, .{data});
}
// 等待所有线程完成
for (threads) |thread| {
thread.join();
}
const expected_total = num_threads * iterations_per_thread;
const actual_total = counter.get();
std.debug.print("\\n=== 测试结果 ===\\n", .{});
std.debug.print("期望总计: {}\\n", .{expected_total});
std.debug.print("实际总计: {}\\n", .{actual_total});
std.debug.print("测试状态: {s}\\n", .{
if (actual_total == expected_total) "✅ 通过" else "❌ 失败"
});
}
package main
import (
"fmt"
"log"
"sync"
"time"
)
type Counter struct {
value int64
mu sync.Mutex
}
func NewCounter() *Counter {
return &Counter{
value: 0,
}
}
func (c *Counter) Increment(amount int64) {
c.mu.Lock()
defer c.mu.Unlock()
c.value += amount
}
func (c *Counter) Get() int64 {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func worker(id int, counter *Counter, iterations int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < iterations; i++ {
counter.Increment(1)
// 模拟一些工作
if i%1000 == 0 {
time.Sleep(time.Nanosecond)
}
}
fmt.Printf("Goroutine %d completed %d iterations\\n", id, iterations)
}
func main() {
const numGoroutines = 4
const iterationsPerGoroutine = 10000
counter := NewCounter()
fmt.Println("Starting concurrent counter test...")
fmt.Printf("Goroutines: %d, Iterations per goroutine: %d\\n",
numGoroutines, iterationsPerGoroutine)
var wg sync.WaitGroup
wg.Add(numGoroutines)
startTime := time.Now()
// 启动所有 goroutines
for i := 0; i < numGoroutines; i++ {
go worker(i, counter, iterationsPerGoroutine, &wg)
}
// 等待所有 goroutines 完成
wg.Wait()
elapsed := time.Since(startTime)
expectedTotal := numGoroutines * iterationsPerGoroutine
actualTotal := counter.Get()
fmt.Println("\\n=== 测试结果 ===")
fmt.Printf("期望总计: %d\\n", expectedTotal)
fmt.Printf("实际总计: %d\\n", actualTotal)
fmt.Printf("执行时间: %v\\n", elapsed)
if actualTotal == expectedTotal {
fmt.Println("测试状态: ✅ 通过")
} else {
fmt.Println("测试状态: ❌ 失败")
}
}
实现一个简单的内存池分配器,展示 Zig 在系统编程方面的强大能力。 Go 无法实现同等功能,因此这个示例重点展示 Zig 的独特优势。
const std = @import("std");
const MemoryPool = struct {
buffer: []u8,
chunk_size: usize,
used: []bool,
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator, total_size: usize, chunk_size: usize) !MemoryPool {
const num_chunks = total_size / chunk_size;
const buffer = try allocator.alloc(u8, total_size);
const used = try allocator.alloc(bool, num_chunks);
@memset(used, false);
return MemoryPool{
.buffer = buffer,
.chunk_size = chunk_size,
.used = used,
.allocator = allocator,
};
}
pub fn deinit(self: *MemoryPool) void {
self.allocator.free(self.buffer);
self.allocator.free(self.used);
}
pub fn allocate(self: *MemoryPool) ?[]u8 {
for (self.used, 0..) |is_used, i| {
if (!is_used) {
self.used[i] = true;
const offset = i * self.chunk_size;
return self.buffer[offset .. offset + self.chunk_size];
}
}
return null;
}
pub fn deallocate(self: *MemoryPool, ptr: []u8) void {
const offset = @intFromPtr(ptr.ptr) - @intFromPtr(self.buffer.ptr);
const chunk_index = offset / self.chunk_size;
if (chunk_index < self.used.len) {
self.used[chunk_index] = false;
}
}
pub fn usage(self: *MemoryPool) struct { used: usize, total: usize } {
var used_count: usize = 0;
for (self.used) |is_used| {
if (is_used) used_count += 1;
}
return .{
.used = used_count,
.total = self.used.len,
};
}
};
const DataObject = struct {
id: u32,
value: f64,
name: [32]u8,
pub fn init(id: u32, value: f64, name: []const u8) DataObject {
var obj = DataObject{
.id = id,
.value = value,
.name = std.mem.zeroes([32]u8),
};
@memcpy(obj.name[0..name.len], name);
return obj;
}
pub fn print(self: *const DataObject) void {
std.debug.print("DataObject{{ id: {}, value: {d:.2}, name: '{s}' }}\\n", .{
self.id, self.value, std.mem.sliceTo(&self.name, 0)
});
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("=== 内存池分配器演示 ===\\n\\n", .{});
// 创建内存池
var pool = try MemoryPool.init(allocator, 1024, 64); // 1KB 池,64 字节块
defer pool.deinit();
std.debug.print("内存池创建完成:\\n", .{});
std.debug.print("总大小: {} 字节\\n", .{pool.buffer.len});
std.debug.print("块大小: {} 字节\\n", .{pool.chunk_size});
std.debug.print("块数量: {}\\n\\n", .{pool.used.len});
// 分配和使用的对象
var objects: [10]?*DataObject = std.mem.zeroes([10]?*DataObject);
// 分配一些对象
for (&objects, 0..) |*obj_ptr, i| {
if (pool.allocate()) |mem| {
const obj = @ptrCast(*DataObject, @alignCast(@alignOf(DataObject), mem.ptr));
obj.* = DataObject.init(@intCast(i), @as(f64, @floatFromInt(i)) * 3.14, "Object");
obj_ptr.* = obj;
std.debug.print("分配对象 {}: ", .{i});
obj.print();
} else {
std.debug.print("无法分配对象 {}: 内存池已满\\n", .{i});
}
}
// 显示内存使用情况
const usage = pool.usage();
std.debug.print("\\n内存使用情况:\\n", .{});
std.debug.print("已使用块: {} / {}\\n", .{ usage.used, usage.total });
std.debug.print("使用率: {d:.1}%\\n\\n", .{
@as(f64, @floatFromInt(usage.used)) / @as(f64, @floatFromInt(usage.total)) * 100.0
});
// 释放一些对象
if (objects[5]) |obj| {
pool.deallocate(@as([]u8, @ptrCast(obj))[0..@sizeOf(DataObject)]);
objects[5] = null;
std.debug.print("释放对象 5\\n", .{});
}
if (objects[7]) |obj| {
pool.deallocate(@as([]u8, @ptrCast(obj))[0..@sizeOf(DataObject)]);
objects[7] = null;
std.debug.print("释放对象 7\\n", .{});
}
// 重新分配
if (pool.allocate()) |mem| {
const obj = @ptrCast(*DataObject, @alignCast(@alignOf(DataObject), mem.ptr));
obj.* = DataObject.init(100, 42.0, "Reused");
std.debug.print("\\n重新分配: ", .{});
obj.print();
}
// 最终内存使用情况
const final_usage = pool.usage();
std.debug.print("\\n最终内存使用情况:\\n", .{});
std.debug.print("已使用块: {} / {}\\n", .{ final_usage.used, final_usage.total });
std.debug.print("使用率: {d:.1}%\\n", .{
@as(f64, @floatFromInt(final_usage.used)) / @as(f64, @floatFromInt(final_usage.total)) * 100.0
});
}
对比 Zig 和 Go 在不同算法上的性能表现,包括排序、数学计算和字符串处理。 了解两种语言在性能敏感场景下的优劣势。
const std = @import("std");
const time = std.time;
const Benchmark = struct {
name: []const u8,
func: fn () void,
iterations: usize,
};
// 冒泡排序实现
fn bubbleSort(arr: []i32) void {
var i: usize = 0;
while (i < arr.len - 1) : (i += 1) {
var j: usize = 0;
while (j < arr.len - i - 1) : (j += 1) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 斐波那契数列计算
fn fibonacci(n: u32) u64 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 素数检查
fn isPrime(n: u64) bool {
if (n < 2) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
var i: u64 = 3;
while (i * i <= n) : (i += 2) {
if (n % i == 0) return false;
}
return true;
}
// 字符串处理
fn processStrings() void {
const strings = [_][]const u8{
"Hello", "World", "Zig", "Programming", "Language",
"Performance", "Optimization", "Benchmark", "Testing", "Example"
};
var i: usize = 0;
while (i < 1000) : (i += 1) {
for (strings) |str| {
_ = std.mem.len(str);
var buffer: [100]u8 = undefined;
_ = std.fmt.bufPrint(&buffer, "{s}_{d}", .{ str, i }) catch continue;
}
}
}
// 基准测试函数
fn runBenchmark(b: Benchmark) void {
std.debug.print("开始测试: {s}\\n", .{b.name});
const start = time.milliTimestamp();
var i: usize = 0;
while (i < b.iterations) : (i += 1) {
b.func();
}
const end = time.milliTimestamp();
const duration = end - start;
std.debug.print(" 迭代次数: {}\\n", .{b.iterations});
std.debug.print(" 总时间: {}ms\\n", .{duration});
std.debug.print(" 平均时间: {d:.3}ms\\n", .{
@as(f64, @floatFromInt(duration)) / @as(f64, @floatFromInt(b.iterations))
});
std.debug.print(" 每秒操作数: {d:.0}\\n\\n", .{
@as(f64, @floatFromInt(b.iterations)) / (@as(f64, @floatFromInt(duration)) / 1000.0)
});
}
pub fn main() !void {
std.debug.print("=== Zig 性能基准测试 ===\\n\\n", .{});
// 准备测试数据
var arr: [100]i32 = undefined;
for (&arr, 0..) |*item, i| {
item.* = @intCast(100 - i);
}
const benchmarks = [_]Benchmark{
.{
.name = "冒泡排序(100元素)",
.func = fn () void {
var test_arr: [100]i32 = arr;
bubbleSort(&test_arr);
},
.iterations = 1000,
},
.{
.name = "斐波那契(30)",
.func = fn () void {
_ = fibonacci(30);
},
.iterations = 10,
},
.{
.name = "素数检查(10000)",
.func = fn () void {
var i: u64 = 2;
while (i < 10000) : (i += 1) {
_ = isPrime(i);
}
},
.iterations = 1,
},
.{
.name = "字符串处理",
.func = processStrings,
.iterations = 100,
},
};
for (benchmarks) |benchmark| {
runBenchmark(benchmark);
}
std.debug.print("=== 测试完成 ===\\n", .{});
}
package main
import (
"fmt"
"strings"
"time"
)
// 冒泡排序实现
func bubbleSort(arr []int) {
n := len(arr)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
// 斐波那契数列计算
func fibonacci(n int) uint64 {
if n <= 1 {
return uint64(n)
}
return fibonacci(n-1) + fibonacci(n-2)
}
// 素数检查
func isPrime(n uint64) bool {
if n < 2 {
return false
}
if n == 2 {
return true
}
if n%2 == 0 {
return false
}
for i := uint64(3); i*i <= n; i += 2 {
if n%i == 0 {
return false
}
}
return true
}
// 字符串处理
func processStrings() {
stringsList := []string{
"Hello", "World", "Go", "Programming", "Language",
"Performance", "Optimization", "Benchmark", "Testing", "Example"
}
for i := 0; i < 1000; i++ {
for _, str := range stringsList {
_ = len(str)
_ = fmt.Sprintf("%s_%d", str, i)
}
}
}
// 基准测试函数
type Benchmark struct {
name string
fn func()
iterations int
}
func runBenchmark(b Benchmark) {
fmt.Printf("开始测试: %s\\n", b.name)
start := time.Now()
for i := 0; i < b.iterations; i++ {
b.fn()
}
duration := time.Since(start)
avgDuration := duration.Seconds() * 1000 / float64(b.iterations)
opsPerSecond := float64(b.iterations) / duration.Seconds()
fmt.Printf(" 迭代次数: %d\\n", b.iterations)
fmt.Printf(" 总时间: %v\\n", duration)
fmt.Printf(" 平均时间: %.3fms\\n", avgDuration)
fmt.Printf(" 每秒操作数: %.0f\\n\\n", opsPerSecond)
}
func main() {
fmt.Println("=== Go 性能基准测试 ===\\n")
// 准备测试数据
arr := make([]int, 100)
for i := range arr {
arr[i] = 100 - i
}
benchmarks := []Benchmark{
{
name: "冒泡排序(100元素)",
fn: func() {
testArr := make([]int, len(arr))
copy(testArr, arr)
bubbleSort(testArr)
},
iterations: 1000,
},
{
name: "斐波那契(30)",
fn: func() { fibonacci(30) },
iterations: 10,
},
{
name: "素数检查(10000)",
fn: func() {
for i := uint64(2); i < 10000; i++ {
isPrime(i)
}
},
iterations: 1,
},
{
name: "字符串处理",
fn: processStrings,
iterations: 100,
},
}
for _, benchmark := range benchmarks {
runBenchmark(benchmark)
}
fmt.Println("=== 测试完成 ===")
}