← Назад к вопросам

Как использовал семафоры или аналогичные механизмы в других языках?

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 с семафорами.

Как использовал семафоры или аналогичные механизмы в других языках? | PrepBro