Introdução
Timers e sleep são fundamentais para controlar o fluxo temporal de programas: pausar entre operações, implementar polling, criar intervalos periódicos e medir duração de operações. Zig oferece funções precisas para isso em std.time.
Nesta receita, você aprenderá a pausar a execução, medir tempo e criar timers.
Pré-requisitos
- Zig instalado (versão 0.13+). Veja o guia de instalação
- Conhecimento básico de Zig. Consulte a introdução ao Zig
Sleep Básico
const std = @import("std");
pub fn main() !void {
std.debug.print("Iniciando...\n", .{});
// Pausar por 1 segundo
std.debug.print("Pausando 1 segundo...\n", .{});
std.time.sleep(std.time.ns_per_s * 1);
// Pausar por 500 milissegundos
std.debug.print("Pausando 500ms...\n", .{});
std.time.sleep(std.time.ns_per_ms * 500);
// Pausar por 100 microssegundos
std.debug.print("Pausando 100us...\n", .{});
std.time.sleep(std.time.ns_per_us * 100);
std.debug.print("Concluído!\n", .{});
}
Timer para Medir Duração
const std = @import("std");
pub fn main() !void {
// Iniciar timer
var timer = try std.time.Timer.start();
// Simular trabalho
std.time.sleep(std.time.ns_per_ms * 250);
// Ler tempo decorrido
const elapsed = timer.read();
std.debug.print("Tempo decorrido: {d} ns\n", .{elapsed});
std.debug.print("Tempo decorrido: {d:.2} ms\n", .{
@as(f64, @floatFromInt(elapsed)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
});
// Resetar timer
timer.reset();
// Outra medição
std.time.sleep(std.time.ns_per_ms * 100);
const elapsed2 = timer.read();
std.debug.print("Segunda medição: {d:.2} ms\n", .{
@as(f64, @floatFromInt(elapsed2)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
});
// Lap (intervalo desde o último lap/start)
timer.reset();
std.time.sleep(std.time.ns_per_ms * 50);
const lap1 = timer.lap();
std.time.sleep(std.time.ns_per_ms * 100);
const lap2 = timer.lap();
std.debug.print("Lap 1: {d:.2} ms\n", .{
@as(f64, @floatFromInt(lap1)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
});
std.debug.print("Lap 2: {d:.2} ms\n", .{
@as(f64, @floatFromInt(lap2)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
});
}
Intervalo Periódico
const std = @import("std");
pub fn main() !void {
const intervalo_ms: u64 = 500;
const max_iteracoes: u32 = 5;
std.debug.print("Executando a cada {d}ms ({d} vezes):\n", .{ intervalo_ms, max_iteracoes });
var timer = try std.time.Timer.start();
for (0..max_iteracoes) |i| {
const tempo_total = timer.read();
const ms = @as(f64, @floatFromInt(tempo_total)) / std.time.ns_per_ms;
std.debug.print(" [{d}] t={d:.0}ms - Executando tarefa...\n", .{ i, ms });
// Simular trabalho (tempo variável)
std.time.sleep(std.time.ns_per_ms * 50);
// Sleep pelo restante do intervalo
const trabalho = timer.lap();
const sleep_ns = (intervalo_ms * std.time.ns_per_ms) -| trabalho;
if (sleep_ns > 0) {
std.time.sleep(sleep_ns);
}
_ = timer.lap(); // Reset lap para próxima iteração
}
const total = timer.read();
std.debug.print("\nTempo total: {d:.0}ms\n", .{
@as(f64, @floatFromInt(total)) / std.time.ns_per_ms,
});
}
Timeout para Operações
const std = @import("std");
fn operacaoComTimeout(timeout_ms: u64) !bool {
var timer = try std.time.Timer.start();
const timeout_ns = timeout_ms * std.time.ns_per_ms;
// Simular operação que verifica periodicamente
var tentativas: u32 = 0;
while (true) {
tentativas += 1;
// Verificar timeout
if (timer.read() >= timeout_ns) {
std.debug.print(" Timeout após {d} tentativas\n", .{tentativas});
return false;
}
// Simular verificação (ex: poll de recurso)
if (tentativas == 5) {
std.debug.print(" Sucesso após {d} tentativas\n", .{tentativas});
return true;
}
std.time.sleep(std.time.ns_per_ms * 100);
}
}
pub fn main() !void {
std.debug.print("Teste 1 (timeout curto - 300ms):\n", .{});
const r1 = try operacaoComTimeout(300);
std.debug.print("Resultado: {}\n\n", .{r1});
std.debug.print("Teste 2 (timeout longo - 2000ms):\n", .{});
const r2 = try operacaoComTimeout(2000);
std.debug.print("Resultado: {}\n", .{r2});
}
Formatar Duração Legível
const std = @import("std");
fn formatarDuracao(ns: u64) struct { valor: f64, unidade: []const u8 } {
if (ns < std.time.ns_per_us) {
return .{ .valor = @floatFromInt(ns), .unidade = "ns" };
} else if (ns < std.time.ns_per_ms) {
return .{
.valor = @as(f64, @floatFromInt(ns)) / std.time.ns_per_us,
.unidade = "us",
};
} else if (ns < std.time.ns_per_s) {
return .{
.valor = @as(f64, @floatFromInt(ns)) / std.time.ns_per_ms,
.unidade = "ms",
};
} else {
return .{
.valor = @as(f64, @floatFromInt(ns)) / std.time.ns_per_s,
.unidade = "s",
};
}
}
pub fn main() !void {
const duracoes = [_]u64{
500, // 500 ns
15_000, // 15 us
3_500_000, // 3.5 ms
1_200_000_000, // 1.2 s
};
for (duracoes) |ns| {
const f = formatarDuracao(ns);
std.debug.print("{d} ns = {d:.2} {s}\n", .{ ns, f.valor, f.unidade });
}
}
Dicas e Boas Práticas
sleepaceita nanossegundos: Use constantes comons_per_spara legibilidade.Timer.lap() para intervalos: Mede o tempo desde o último
lap()oustart().Saturação em timeouts: Use
-|(subtração saturada) para evitar underflow ao calcular tempo restante.Sleep não é preciso: A precisão depende do SO. Não use para temporização exata.
Receitas Relacionadas
- Time e Timestamps - Obter tempo atual
- Benchmark e Performance - Medir performance
- Criar e Gerenciar Threads - Threads com sleep
- Sinais do Sistema - Interromper sleeps