← Назад к вопросам
Как использовал семафоры или аналогичные механизмы в других языках?
1.7 Middle🔥 151 комментариев
#Python Core#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Семафоры и синхронизационные механизмы в различных языках
Семафоры — это примитивы синхронизации для контроля доступа к общим ресурсам. Применял их в Python и других языках для решения задач параллелизма.
Python: Threading Semaphore
Для ограничения количества потоков, одновременно обращающихся к ресурсу:
import threading
import time
# Максимум 3 потока одновременно
semaphore = threading.Semaphore(3)
def worker(worker_id):
with semaphore: # Автоматическое acquire/release
print(f"Worker {worker_id} начал")
time.sleep(2)
print(f"Worker {worker_id} закончил")
threads = []
for i in range(10):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
Python: asyncio Semaphore
Для ограничения одновременных асинхронных операций:
import asyncio
async def fetch_url(session, url, semaphore):
async with semaphore: # Максимум 5 одновременных запросов
print(f"Fetching {url}")
# Имитация HTTP запроса
await asyncio.sleep(1)
return f"Data from {url}"
async def main():
semaphore = asyncio.Semaphore(5)
urls = [f"https://api.example.com/item/{i}" for i in range(20)]
tasks = [fetch_url(None, url, semaphore) for url in urls]
results = await asyncio.gather(*tasks)
return results
asyncio.run(main())
Python: Lock (бинарный семафор)
Для защиты критических секций кода от race conditions:
import threading
lock = threading.Lock()
counter = 0
def increment():
global counter
with lock: # Гарантирует эксклюзивный доступ
temp = counter
temp += 1
counter = temp
threads = [threading.Thread(target=increment) for _ in range(100)]
for t in threads:
t.start()
for t in threads:
t.join()
print(counter) # Будет 100, а не случайное число
Python: RLock (рекурсивный семафор)
Позволяет одному потоку несколько раз захватить блокировку:
import threading
rlock = threading.RLock()
def outer():
with rlock:
print("Outer acquired lock")
inner()
def inner():
with rlock: # Тот же поток может захватить снова
print("Inner acquired lock")
t = threading.Thread(target=outer)
t.start()
t.join()
Go: Channels (аналог семафора)
В Go для синхронизации используются каналы:
package main
import (
"fmt"
"time"
)
func worker(id int, semaphore chan bool) {
semaphore <- true // Acquire
defer func() { <-semaphore }() // Release
fmt.Printf("Worker %d начал\n", id)
time.Sleep(2 * time.Second)
fmt.Printf("Worker %d закончил\n", id)
}
func main() {
semaphore := make(chan bool, 3) // Max 3 одновременно
for i := 0; i < 10; i++ {
go worker(i, semaphore)
}
// Wait
for i := 0; i < 3; i++ {
semaphore <- true
}
}
Go: sync.Semaphore альтернатива
package main
import (
"fmt"
"sync"
"time"
)
type Semaphore struct {
sem chan struct{}
}
func NewSemaphore(max int) *Semaphore {
return &Semaphore{sem: make(chan struct{}, max)}
}
func (s *Semaphore) Acquire() {
s.sem <- struct{}{}
}
func (s *Semaphore) Release() {
<-s.sem
}
func main() {
sem := NewSemaphore(3)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
sem.Acquire()
defer sem.Release()
fmt.Printf("Worker %d\n", id)
time.Sleep(time.Second)
}(i)
}
wg.Wait()
}
Java: Semaphore
import java.util.concurrent.Semaphore;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SemaphoreExample {
static class Worker implements Runnable {
private final Semaphore semaphore;
private final int id;
Worker(Semaphore semaphore, int id) {
this.semaphore = semaphore;
this.id = id;
}
@Override
public void run() {
try {
semaphore.acquire(); // Acquire
System.out.println("Worker " + id + " started");
Thread.sleep(2000);
System.out.println("Worker " + id + " finished");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release(); // Release
}
}
}
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(new Worker(semaphore, i));
}
executor.shutdown();
}
}
Практические применения
Ограничение подключений к БД:
- Использую семафоры для контроля размера connection pool
Rate limiting:
- Контролирую количество одновременных HTTP запросов
Защита критических секций:
- Когда обновляю общее состояние из множества потоков
Асинхронный crawler:
- Ограничиваю одновременные запросы к серверу через asyncio.Semaphore
Выбор между потоками и асинхронностью зависит от типа задачи: CPU-bound лучше multiprocessing, I/O-bound — asyncio с семафорами.