Pull to refresh
0
Сергей@Sega100500

инженер-программист

1
Subscribers
Send message

Сегодня aptitude с debian.org - ооочень медленно (10-30Kb/s) качалось новое ядро.
"Профессионалы" РКН во всей красе - браво ё-маё!

да-да-да, Ruby чуть ли ни с рождения хоронят... всё никак похоронить не могут ;-) )))

https://inet777.ru/ruby-is-dead

Каждый раз приятно удивляюсь, как с каждым следующим релизом Ruby работает всё быстрее и быстрее, особенно с YJIT - среди интерпретируемых языков равных нет - все остальные нервно курят в сторонке.

Особенно порадовало совершенно безболезненное обновление до версии Ruby 4.0.0 - установил Ruby (через rbenv), установил gem-ы (всего лишь bundle install; bundle update) - и все сайты на Ruby on Rails 8.1.x заработали!... только ещё быстрее, чем прежде!

Браво! Вот это язык, вот это система! Очень впечатляет развитие! Но в то же время и стабильность, зрелость языка! Так держать! Ruby, с Юбилеем! :-)

Для начала я бы посоветовал (скромно) автору всё же получше изучить Rust (если это вообще в принципе возможно для питониста (в чём я, честно говоря, сомневаюсь)). Даже в столь простом примере вы умудрились сделать ошибки - сравните хотя бы свой пример с тем же самым, но на странице библиотеки PyO3, о которой вы сами говорите.
Я далеко не сторонник "питуха", а скорее даже наоборот, поэтому я думаю, что сама по себе эта идея, мягко выражаясь, не очень - изобретать на Rust очередные костыли для python.

Относительно недавно была издана книга
"Programming Rust SECOND EDITION Fast, Safe Systems Development"
Jim Blandy, Jason Orendorff, and
Leonora F.S. Tindall
(2021 год)
Если какое-то издательство выпустит перевод её - это будет очень полезным материалом для изучения Rust. Первая редакция этой книги - это лучший материал для изучения Rust на русском языке, который я видел.
Я уже написал электронное письмо в издательство ДМК-пресс (они выпустили перевод первой редакции этой книги "Язык программирования Rust" (2018 год)) с просьбой выпустить перевод и второй редакции этой полезной книги. Посмотрим, что получится... Не только же информацией про популярный ныне Питух пытаться кормить всех...

Могу посоветовать автору обратить внимание на язык программирования Ruby (вместо PHP, а уж тем более Python) - связка Ruby + Rust обещает быть очень перспективной. В Ruby включена поддержка связки с кодом Rust на уровне самой системы языка "bundle gem --ext=rust" - с использованием Magnus (rb_sys).
Сам по себе Ruby уже сейчас использует Rust (для компиляции с поддержкой YJIT требуется установка Rust).
Ruby обладает понятным, логичным и красивым синтаксисом, на Rust можно реализовывать критичные к скорости и безопасности участки кода.

Чтобы устранить путаницу, вот правило нумерации версий Ruby. Да, немного путаница с терминологией, т.к. в номере версии присутствует ещё и номер TEENY:

Номера версий имеют следующее значение:

  • MAJOR — увеличивается при несовместимом изменении, которое не может быть выпущено в MINOR.

  • MINOR — увеличивается каждый раз, может быть несовместима с API.

  • TEENY — исправление безопасности или ошибки, которое сохраняет совместимость API. Может быть увеличено более чем на 10 (например, 2.1.11) и выпускается каждые 2–3 месяца.

  • PATCH — количество коммитов с последнего выпуска MINOR (при выпуске MINOR сбрасывается на 0).

Да, действительно, есть некоторая путаница - минорная версия - это третья цифра в номере версии, а не вторая. После 3.3.xxx идёт версия 3.4.xxx - и это уже с некоторыми изменениями, дополнениями в языке. А далее внутри этих веток уже меняется минорная часть xxx - это как раз и есть исправления ошибок в самой этой "ветке", версии языка.

Скажем так, если меняется первая цифра, то это вообще очень существенные изменения в самом языке. Поэтому, я как-то привык рассматривать изменения только 2 и 3 цифр, соответственно, и называю их мажорная и минорная. Извиняюсь за некоторую неточность и собственную интерпретацию.

Но сейчас, я полагаю, смысл изменений в версиях Ruby вам должен быть более понятен.

Ещё раз повторюсь. В этих "параллельных" (как вы их называете) версиях языка есть некоторые отличия в самом языке. Например, в Ruby 3.4 был добавлен в стандарт анонимный аргумент it внутри блоков. Ранее были добавлены другие возможности языка. Вся эволюция описана тут: https://rubyreferences.github.io/rubychanges/evolution.html
Минорные версии - это исправления ошибок и некоторые улучшения в ветке без изменений в самом языке.

Ruby постоянно улучшается, в язык добавляются новые возможности.
Изменения в версиях описаны, например, здесь:
https://rubyreferences.github.io/rubychanges/

+1

У Ruby много чего и более приятного есть, чего у Python нет и не будет никогда. А Ruby тем временем развивается и улучшается - становится всё лучше, удобнее, мощнее и быстрее.
Python выбран математиками за простоту (им ни к чему разбираться ещё и в программировании), а для программиста эта (кажущаяся) простота, зачастую - ущербность.

"Просто нет другого языка, который мог бы сравниться с Perl по возможностям обработки текста"
Чушь полная! Пока Perl "отсутствовал" (скажем так) в других языках давно уже были реализованы все возможности, которыми обладал Perl.
Регулярные выражения? PHP, Python, в Ruby вообще поддержка регулярок на уровне языка.

Поломался TIOBE, однозначно поломался!... либо кто-то занимается маркетингом с помощью него.

Самое разумное - рассматривать этот рейтинг как "собака лает, караван идёт" - ни жарко, ни холодно от него, но порой весело.

Ну и всё же вдогонку пример с Ractor, но с ruby-kafka вместо rdkafka. Чтоб тебе совсем не скучать! ))) Как видишь, вариантов решения на Ruby может быть множество, но только я понимаю, что это совсем не о тебе - ты ж великий спец только поумничать, а не найти решение. Про зеркало упомянул?... и это вполне объяснимо - когда заканчиваются аргументы, остаётся последний аргумент: "сам дурак!".

Я в курсе про FFI, rb-sys, Magnus и прочие связки Ruby с нативным кодом. Ты очередной раз мне об этом напомнил, и только ещё раз показал свою тупость. Видимо, ты единственный, кто пишет всё ПОЛНОСТЬЮ сам, без использования любых библиотек, верно? ))) Знаешь, твой код, наверное, настолько "чистый", что ни разу не обращается даже ни к одному системному вызову - только твой собственный идеальный мир.

Вызов в Ruby через FFI - это всего лишь обращение к библиотеке работы с Kafaka. Но для тебя это уже не Ruby! Браво! )))))

Ох и повеселил ты меня, конечно! ))) И где ж таких только раздают, как ты? Ты явно отстал от какого-то цирка. )))

P..S. Ах да, про Rails... Sinatra тут только в том смысле, чтобы тебе понятнее было. Вообще никто не мешает отрабатывать этот 'POST' в контроллере RoR.

P.P.S. Можешь продолжать вякать и дальше - это очень весело! Хоть настроение поднимаешь - и то вперёд! ;-) )))

# encoding: utf-8
# frozen_string_literal: true

require 'sinatra'
require 'kafka'
require 'json'
require 'etc'
require 'mutex_m'

set :bind, '0.0.0.0'
set :port, 4567

BROKERS = ['localhost:9092'] # ruby-kafka ожидает массив
TOPIC = 'events'
WORKERS = Etc.nprocessors
MAX_SIZE = 60_000

# Счётчик обработанных запросов
rps_count = 0
rps_mutex = Mutex.new

# Пул Ractor'ов
worker_index = 0
worker_mutex = Mutex.new

workers = Array.new(WORKERS) do | i |
  Ractor.new(i, BROKERS, TOPIC) do | wid, brokers, topic |

    # Создаём Kafka-клиент и producer внутри Ractor'а
    kafka = Kafka.new(
      seed_brokers: brokers,
      client_id: "collector_worker_#{wid}"
    )

    # Синхронный продюсер (для полного контроля и ACK=all)
    producer = kafka.sync_producer(
      acks: :all,
      max_retries: 3,
      retry_backoff: 100
    )

    loop do

      msg = Ractor.receive

      break if msg == :shutdown

      begin

        # Парсим JSON с символами в ключах
        data = JSON.parse(msg, symbolize_names: true)

        # Фильтрация только разрешённых ключей
        data.slice!(:type, :name, :a, :b)

        # Анализируем сообщения
        case data
        in { type: 'greeting', name: String => name }
          puts "[Ractor #{wid}] Greeting for #{name}"

        in { type: 'sum', a: Integer => a, b: Integer => b }
          puts "[Ractor #{wid}] Sum = #{a + b}"

        else
          puts "[Ractor #{wid}] Unrecognized event"
        end

        # Синхронная отправка (для гарантии ACK=all)
        # Можно использовать async_producer, но sync проще для контроля
        producer.deliver_message(msg, topic: topic)

      rescue JSON::ParserError
        warn "[Ractor #{wid}] Invalid JSON"
      rescue => e
        warn "[Ractor #{wid}] Error: #{e.class} #{e.message}"
      ensure
        # Важно: закрыть продюсер при выходе
        producer&.close
      end

    end

  end
end

# RPS-мониторинг
Thread.new do
  loop do
    sleep 1
    count = rps_mutex.synchronize { rps_count.tap { rps_count = 0 } }
    puts "[RPS] #{count} events/sec"
  end
end

# HTTP endpoint для приёма событий
post '/events' do

  body = request.body.read

  halt 413, 'Payload too large' if body.bytesize > MAX_SIZE
  halt 400, 'Empty payload' if body.empty?

  # Считаем RPS
  rps_mutex.synchronize { rps_count += 1 }

  # Round-robin выбор Ractor'а
  worker_idx = worker_mutex.synchronize { (worker_index += 1) % WORKERS }
  workers[worker_idx].send(body)

  status 202
  'Accepted'

end

# Завершение работы
at_exit do

  puts "[Main] Shutting down..."

  # Остановить Ractor'ы
  workers.each { | w | w.send(:shutdown) }
  workers.each(&:take)

  puts "[Main] All workers stopped."

end

ну и вот ещё вариантик... сиди разбирайся! заодно может хоть чуть-чуть с матчастью ознакомишься, "профессор" хренов! )))

# encoding: utf-8
# frozen_string_literal: true

require 'sinatra'
require 'rdkafka'
require 'json'
require 'etc'
require 'thread'

set :bind, '0.0.0.0'
set :port, 4567

BROKERS = 'localhost:9092'
TOPIC = 'events'
WORKERS = Etc.nprocessors
MAX_SIZE = 60_000
MAX_QUEUE_SIZE = 10_000

# Конфиг Kafka
RDKAFKA_CONFIG = {
  'bootstrap.servers'      => BROKERS,
  'acks'                   => 'all',
  'queue.buffering.max.ms' => '5',
  'batch.num.messages'     => '10000'
}

# === Первая очередь: для передачи событий в Ractor'ы (backpressure) ===
input_queue = SizedQueue.new(MAX_QUEUE_SIZE)

# === Вторая очередь: для отправки обработанных данных в Kafka ===
events_queue = SizedQueue.new(MAX_QUEUE_SIZE)

# === Главный producer (в main потоке) ===
producer = Rdkafka::Config.new(RDKAFKA_CONFIG).producer

# === Поток отправки в Kafka (из main потока) ===
# Запускаем фоновую отправку из main потока
# Поток отправки сообщений в Kafka (решает проблему Ractor::IsolationError в rdkafka)
# потому как rdkafka какого-то чёрта использует переменные класса, хотя давно
# всем известно, что их использование не рекомендует даже Matz
# поэтому работа с kafka будет производится в главном потоке
Thread.new do
  loop do

    msg = events_queue.pop

    break if msg == :flush

    begin
      producer.produce_async(topic: TOPIC, payload: msg)
      producer.poll(0)
    rescue => e
      warn "[Kafka Thread] Error: #{e.class} #{e.message}"
    end

  end
end

# === Пул Ractor'ов: читают из input_queue, обрабатывают, отправляют в events_queue ===
rps_count = 0
rps_mutex = Mutex.new

workers = Array.new(WORKERS) do | i |
  Ractor.new(i, input_queue, events_queue) do | wid, input, output |

    loop do

      msg = input.pop # читаем из очереди ввода

      break if msg == :shutdown

      begin

        data = JSON.parse(msg, symbolize_names: true)

        data.slice!(:type, :name, :a, :b)

        case data
        in { type: 'greeting', name: String => name }
          puts "[Ractor #{wid}] Greeting for #{name}"
        in { type: 'sum', a: Integer => a, b: Integer => b }
          puts "[Ractor #{wid}] Sum = #{a + b}"
          else
            puts "[Ractor #{wid}] Unrecognized event"
        end

        output << msg # в очередь для отправки в kafka

      rescue JSON::ParserError
        warn "[Ractor #{wid}] Invalid JSON"
      rescue => e
        warn "[Ractor #{wid}] Error: #{e.class} #{e.message}"
      end

    end

  end
end

# === RPS-мониторинг ===
Thread.new do
  loop do
    sleep 1
    count = rps_mutex.synchronize { rps_count.tap { rps_count = 0 } }
    puts "[RPS] #{count} events/sec"
  end
end

# === HTTP endpoint для приёма событий ===
post '/events' do

  body = request.body.read

  halt 413, 'Payload too large' if body.bytesize > MAX_SIZE
  halt 400, 'Empty payload' if body.empty?

  rps_mutex.synchronize { rps_count += 1 }

  begin
    input_queue.push(body, exception: false)
  rescue ThreadError
    halt 429, 'Too many requests'
  end

  status 202
  'Accepted'

end

# === Завершение работы ===
at_exit do

  puts "[Main] Shutting down..."

  # 1. Отправить сигнал завершения всем Ractor'ам
  workers.each { | worker | worker.send(:shutdown) }

  # 2. Дождаться завершения всех Ractor'ов
  workers.each(&:take)

  # 3. Отправить сигнал завершения потоку Kafka
  events_queue << :flush

  # 4. Дождаться отправки всех сообщений
  producer&.flush(5000)

  puts "[Main] All workers stopped."

end

Слушай, ты, ограниченная умственной способностью сущность, - в твоей голове, похоже, вместо мозга только набор терминов и дешёвых понтов. С чего ты возомнил себя здесь профессором? Оценки он тут расставляет. Я не студент, и уж тем более не собираюсь слушать тебя, «учителя» с слабоумным подходом. Я предложил конкретные решения, в отличие от тебя, который даже не смог разобраться в элементарном коде, а уж о решениях и речи не идет.

Если у вас Kafka падает, то это никак не проблемы кода. Если до тебя не доходит, попробуй хотя бы немного поработать с этим кодом, исправить конфигурацию Kafka - это называется инженерный подход.

Мне глубоко параллельно, что ты думаешь обо мне. Ты уже успел блеснуть своим скудоумием на Хабре - умные люди давно поняли, кто ты на самом деле (если кто-то читает эту тему). А если у тебя в голове только «это невозможно», то это твои проблемы и, кстати, проблемы твоих работодателей, которые так и не получают нужного результата.

Мне немного стала интересна задача, вот и решил попробовать. Вот тебе ещё вариант. Но это уже точно последний. Не думаю, что ты в этом что-то поймёшь, но мне уже на это наплевать.

# encoding: utf-8
# frozen_string_literal: true

require 'sinatra'
require 'rdkafka'
require 'json'
require 'etc'
require 'mutex_m'

set :bind, '0.0.0.0'
set :port, 4567

BROKERS = 'localhost:9092'
TOPIC = 'events'
WORKERS = Etc.nprocessors
MAX_SIZE = 60_000
MAX_QUEUE_SIZE = 10000  # Максимальный размер очереди

# Конфиг Kafka
RDKAFKA_CONFIG = {
  'bootstrap.servers'      => BROKERS,
  'acks'                   => 'all',
  'queue.buffering.max.ms' => '5',
  'batch.num.messages'     => '10000'
}

# === Очередь для передачи данных из Ractor'ов в главный поток ===
# Используем SizedQueue для ограничения размера очереди
events_queue = SizedQueue.new(MAX_QUEUE_SIZE)

# === Главный producer (в main потоке) ===
producer = Rdkafka::Config.new(RDKAFKA_CONFIG).producer

# Запускаем фоновую отправку из main потока 
# Поток отправки сообщений в Kafka (решает проблему Ractor::IsolationError в rdkafka) 
# потому как rdkafka какого-то чёрта использует переменные класса, хотя давно 
# всем известно, что их использование не рекомендует даже Matz
# поэтому работа с kafka будет производится в главном потоке
Thread.new do
  loop do

    msg = events_queue.pop # Блокируется, пока не появится сообщение

    next if msg == :flush  # Сигнал на завершение

    begin
      producer.produce_async(topic: TOPIC, payload: msg)
      producer.poll(0) # Обработка колбэков
    rescue => e
      warn "[Kafka Thread] Error: #{e.class} #{e.message}"
    end

  end
end

# === Пул Ractor'ов (только обработка) ===
rps_count = 0
rps_mutex = Mutex.new
worker_index = 0
worker_mutex = Mutex.new

workers = Array.new(WORKERS) do | i |
  Ractor.new(i, events_queue) do | wid, queue |

    loop do

      msg = Ractor.receive
      break if msg == :shutdown

      begin

        # Парсим JSON с символами в ключах
        data = JSON.parse(msg, symbolize_names: true)

        # Фильтрация только разрешённых ключей
        data.slice!(:type, :name, :a, :b)

        # Анализируем сообщения
        case data
        in { type: 'greeting', name: String => name }
          puts "[Ractor #{wid}] Greeting for #{name}"
        in { type: 'sum', a: Integer => a, b: Integer => b }
          puts "[Ractor #{wid}] Sum = #{a + b}"
        else
          puts "[Ractor #{wid}] Unrecognized event"
        end

        # Отправляем в очередь (не в Kafka!)
        queue << msg

      rescue JSON::ParserError
        warn "[Ractor #{wid}] Invalid JSON"
      rescue => e
        warn "[Ractor #{wid}] Error: #{e.class} #{e.message}"
      end

    end

  end
end

# === RPS-мониторинг ===
Thread.new do
  loop do
    sleep 1
    count = rps_mutex.synchronize { rps_count.tap { rps_count = 0 } }
    puts "[RPS] #{count} events/sec"
  end
end

# === HTTP endpoint для приёма событий ===
post '/events' do

  body = request.body.read

  halt 413, 'Payload too large' if body.bytesize > MAX_SIZE
  halt 400, 'Empty payload' if body.empty?

  # Считаем RPS
  rps_mutex.synchronize { rps_count += 1 }

  # Попытка отправить сообщение в очередь
  begin
    # Добавляем сообщение в очередь с отклонением при переполнении
    events_queue.push(body, exception: false)
  rescue ThreadError
    halt 429, 'Too many requests'
  end

  status 202
  'Accepted'

end

# === Завершение работы ===
at_exit do

  puts "[Main] Shutting down..."

  # 1. Остановить Ractor'ы
  workers.each { | w | w.send(:shutdown) }
  workers.each(&:take)

  # 2. Отправить сигнал завершения в поток Kafka
  events_queue << :flush

  # 3. Дождаться отправки всех сообщений
  producer&.flush(5000)

  puts "[Main] All workers stopped."

end

чуть позже заметил ошибку, правильно так:
case data

in { type: 'greeting', name: String => name }

puts "[Ractor #{wid}] Greeting for #{name}"

in { type: 'sum', a: Integer => a, b: Integer => b }

puts "[Ractor #{wid}] Sum = #{a + b}"

else

puts "[Ractor #{wid}] Unrecognized event"

end

Как же сложно иметь дело со всякими "дереволазами", нахватавшимися терминов, а по сути так и оставшимися деревянными по пояс (при чём сверху). Ты сам научись читать и улавливать суть! «ни C, ни Rust тут не нужны» - это было сказано вообще в отношении тех, кто считает, что Ruby с чем-то не справится. Вот тебе даже ни CRUD, а просто POST! Пример на чистом Ruby, но, как я и говорил, с использованием Ractor. Для этого небольшого примера не надо создавать отдельный проект, а уж тем более незачем публиковать его на Git (GitHub). Я хотел тебе прислать на почту, но ты, видимо, предпочитаешь публичное унижение.
Очень печально, что идиотизм пробирается в программистские ряды, очень печально!...
На будущее - не суди о людях по себе, и уж если человек о чём-то упоминает, то наверное он имеет представление, о чём он говорит.
И да, не показывай этот код коллегам, а то, вполне возможно, тебя попрут с твоей работы за твой код, хотя... может он и хорош, не буду утверждать.
P.S. И всё же очень интересно, что у вас там за такие коллосы вычислительные, что способны прожевать 10K x 50K ~= 500Mb/s ... или ты это сам всё придумал ради красного словца?

Вот на этом точно всё! Успехов тебе, умник!

# frozen_string_literal: true

 

require 'sinatra'

require 'rdkafka'

require 'json'

require 'etc'

require 'mutex_m'

 

set :bind, '0.0.0.0'

set :port, 4567

 

BROKERS = 'localhost:9092'

TOPIC = 'events'

WORKERS = Etc.nprocessors

MAX_SIZE = 60_000

 

# Конфиг Kafka

RDKAFKA_CONFIG = {

  'bootstrap.servers' => BROKERS,

  'acks' => 'all',

  'queue.buffering.max.ms' => '5',

  'batch.num.messages' => '10000'

}

 

# Пул Ractor'ов

rps_count = 0

rps_mutex = Mutex.new

worker_index = 0

worker_mutex = Mutex.new

workers = Array.new(WORKERS) do |i|

  Ractor.new(i, RDKAFKA_CONFIG, TOPIC) do |wid, config, topic|

    producer = Rdkafka::Config.new(config).producer

    loop do

      msg = Ractor.receive

      break if msg == :shutdown # Завершаем работу

 

      begin

        # Парсим JSON с символами в ключах

        data = JSON.parse(msg, symbolize_names: true)

 

        # Фильтрация только разрешённых ключей

        data.slice!(:type, :name, :a, :b)

 

        # Анализируем сообщения

        case data

        in { type: :greeting, name: String => name }

          puts "[Ractor #{wid}] Greeting for #{name}"

        in { type: :sum, a: Integer => a, b: Integer => b }

          puts "[Ractor #{wid}] Sum = #{a + b}"

        else

          puts "[Ractor #{wid}] Unrecognized event"

        end

 

        # Асинхронная отправка в Kafka без блокировки

        producer.produce_async(topic: topic, payload: msg)

        producer.poll(0) # Обработка колбэков

 

      rescue JSON::ParserError

        warn "[Ractor #{wid}] Invalid JSON"

      rescue => e

        warn "[Ractor #{wid}] Error: #{e.class} #{e.message}"

      end

    end

  end

end

 

# Выводим количество обработанных событий в секунду

Thread.new do

  loop do

    sleep 1

    count = rps_mutex.synchronize { rps_count.tap { rps_count = 0 } }

    puts "[RPS] #{count} events/sec"

  end

end

 

# HTTP endpoint для приёма событий

post '/events' do

  body = request.body.read

  halt 413, 'Payload too large' if body.bytesize > MAX_SIZE

  halt 400, 'Empty payload' if body.empty?

 

  # Считаем количество запросов в секунду

  rps_mutex.synchronize { rps_count += 1 }

 

  # Используем round-robin для выбора работника

  worker_idx = worker_mutex.synchronize { (worker_index += 1) % WORKERS }

  workers[worker_idx].send(body)

 

  status 202

  'Accepted'

end

 

# Завершаем работу всех Ractor'ов при выходе из программы

at_exit do

  puts "[Main] Shutting down..."

  workers.each { |w| w.send(:shutdown) }

  workers.each(&:take) # ждём завершения

  puts "[Main] All workers stopped."

end


Но это ведь ИИ - очень хороший помощник, если относиться к нему именно как к помощнику, а не как к творцу, то всё очень даже хорошо!

Возможно, именно благодаря ИИ многие программные системы будут приведены в порядок, будут найдены и исправлены ошибки... и Windows после рефакторинга всего кода в итоге превратится... в Linux ! ;-) )))

Забавно, как некоторые уверенно оперируют словами " CPU-bound", “IO-bound” и “GVL”, не понимая, что в реальной системе это совершенно разные вещи. Любой, кто хотя бы читал Баха про архитектуру UNIX, знает, что спящий процесс при ожидании ввода-вывода отдаёт управление планировщику, а в Ruby в этот момент GVL освобождается. Kafka при этом прекрасно жонглирует соединениями, а CPU Ruby даже не успевает заскучать. Поэтому разговоры в духе “тут обязательно нужен Rust или C, иначе всё упрётся” звучат как обсуждение тормозов у велосипеда на парковке: вроде умные слова есть, а контекста — ноль. Советую для начала разобрать, что именно делает планировщик ОС и где на самом деле узкое место, а уже потом жонглировать терминами. Это избавит от неловких ситуаций, когда инженер со стажем слушает лекцию по “матчасти” от человека, который с ней ещё не очень-то знаком. Понахватавшись терминов, ты ещё не становишься автоматически умнее.

Адрес почты напиши. Я тебе вышлю код. Я не собираюсь для тебя оформлять целый проект, ты сам умный - разберёшься что к чему.
Нет адреса - разговор окончен. На этом всё.

1
23 ...

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Registered
Activity

Specialization

Фулстек разработчик, Веб-разработчик
From 100,000 ₽
Ruby
Ruby on Rails
HTML
SCSS
CSS
JQuery
Ajax
MariaDB
Rust
Linux