The Codest
  • O nás
  • Služby
    • Vývoj softwaru
      • Vývoj frontendů
      • Vývoj backendu
    • Staff Augmentation
      • Vývojáři frontendů
      • Vývojáři backendu
      • Datoví inženýři
      • Cloudoví inženýři
      • Inženýři QA
      • Další
    • To Advisory
      • Audit a poradenství
  • Odvětví
    • Fintech a bankovnictví
    • E-commerce
    • Adtech
    • Healthtech
    • Výroba
    • Logistika
    • Automobilový průmysl
    • IOT
  • Hodnota za
    • CEO
    • CTO
    • Manažer dodávek
  • Náš tým
  • Case Studies
  • Vědět jak
    • Blog
    • Setkání
    • Webové semináře
    • Zdroje
Kariéra Spojte se s námi
  • O nás
  • Služby
    • Vývoj softwaru
      • Vývoj frontendů
      • Vývoj backendu
    • Staff Augmentation
      • Vývojáři frontendů
      • Vývojáři backendu
      • Datoví inženýři
      • Cloudoví inženýři
      • Inženýři QA
      • Další
    • To Advisory
      • Audit a poradenství
  • Hodnota za
    • CEO
    • CTO
    • Manažer dodávek
  • Náš tým
  • Case Studies
  • Vědět jak
    • Blog
    • Setkání
    • Webové semináře
    • Zdroje
Kariéra Spojte se s námi
Šipka zpět ZPĚT
2016-10-06
Vývoj softwaru

ROZVĚTVENÍ A ŘAZENÍ VLÁKEN V JAZYCE RUBY

Marek Gierlach

Jak pravděpodobně víte, Ruby má několik implementací, například MRI, JRuby, Rubinius, Opal, RubyMotion atd., a každá z nich může používat jiný vzor provádění kódu. Tento článek se zaměří na první tři z nich a porovná MRI

Jak pravděpodobně víte, Ruby má několik implementací, například MRI, JRuby, Rubinius, Opal, RubyMotion atd., a každá z nich může používat jiný vzor. kód provedení. V tomto článku se zaměříme na první tři z nich a porovnáme MRI (v současnosti nejpopulárnější implementaci) s JRuby a Rubiniusem na základě několika ukázkových skriptů, které mají posoudit vhodnost forkování a threadingu v různých situacích, jako je zpracování algoritmů náročných na výkon procesoru, kopírování souborů apod.Než se začnete "učit praxí", je třeba si zopakovat několik základních pojmů.

Vidlice

  • je nový podřízený proces (kopie rodičovského procesu).
  • má nový identifikátor procesu (PID)
  • má oddělenou paměť*
  • komunikuje s ostatními prostřednictvím meziprocesových komunikačních kanálů (IPC), jako jsou fronty zpráv, soubory, zásuvky atd.
  • existuje i po ukončení nadřazeného procesu
  • je volání POSIX - funguje hlavně na platformách Unix

Vlákno

  • je "pouze" kontextem provádění, který pracuje v rámci procesu.
  • sdílí veškerou paměť s ostatními (ve výchozím nastavení využívá méně paměti než fork).
  • komunikuje s ostatními pomocí objektů sdílené paměti
  • umírá s procesem
  • přináší typické problémy s vícevláknovým zpracováním, jako je hladovění, deadlocky atd.

Existuje spousta nástrojů využívajících forky a vlákna, které se používají denně, např. Unicorn (forky) a Puma (vlákna) na úrovni aplikačních serverů, Resque (forky) a Sidekiq (vlákna) na úrovni úloh na pozadí atd.

Následující tabulka uvádí podporu forkování a threadingu v hlavních implementacích jazyka Ruby.

Implementace jazyka RubyRozvětveníZávitování
MRIAnoAno (s omezením podle GIL**)
JRuby–Ano
RubiniusAnoAno

V tomto tématu se jako bumerang vracejí další dvě magická slova - paralelismus a souběžnost - musíme si je trochu vysvětlit. Především nelze tyto pojmy používat zaměnitelně. Zjednodušeně řečeno - o paralelismu můžeme mluvit tehdy, když se dvě nebo více úloh zpracovávají přesně ve stejnou dobu. O souběhu hovoříme tehdy, když se dvě nebo více úloh zpracovává v časových úsecích, které se překrývají (ne nutně ve stejnou dobu). Ano, je to obecné vysvětlení, ale dostatečně dobré k tomu, abyste si všimli rozdílu a pochopili zbytek tohoto článku.

Fronented Report pro rok 2020

Následující tabulka uvádí podporu paralelismu a souběžnosti.

Implementace jazyka RubyParalelismus (prostřednictvím vidlic)Paralelismus (prostřednictvím vláken)Současnost
MRIAnoNeAno
JRuby–AnoAno
RubiniusAnoAno (od verze 2.X)Ano

To je konec teorie - podívejme se na to v praxi!

  • Samostatná paměť nemusí nutně spotřebovávat stejné množství paměti jako nadřazený proces. Existují některé techniky optimalizace paměti. Jednou z nich je Copy on Write (CoW), která umožňuje rodičovskému procesu sdílet přidělenou paměť s podřízeným procesem, aniž by ji kopíroval. Pomocí CoW je další paměť potřeba pouze v případě modifikace sdílené paměti dětským procesem. V kontextu Ruby není každá implementace CoW přátelská, např. MRI ji plně podporuje od verze 2.X. Před touto verzí každý fork spotřebovával tolik paměti jako rodičovský proces.
  • Jednou z největších výhod/nevýhod MRI (nehodící se alternativu škrtněte) je použití GIL (Global Interpreter Lock). Stručně řečeno, tento mechanismus je zodpovědný za synchronizaci provádění vláken, což znamená, že v jednom okamžiku může být prováděno pouze jedno vlákno. Ale počkat... Znamená to, že v MRI nemá smysl vlákna vůbec používat? Odpověď přichází s pochopením vnitřností GIL... nebo alespoň s nahlédnutím do ukázek kódu v tomto článku.

Testovací případ

Abych představil, jak funguje forkování a threading v implementacích jazyka Ruby, vytvořil jsem jednoduchou třídu s názvem Test a několik dalších, které z něj dědí. Každá třída má jiný úkol, který má zpracovat. Ve výchozím nastavení se každá úloha spustí čtyřikrát ve smyčce. Každá úloha také běží proti třem typům provádění kódu: sekvenčnímu, s vidlicemi a s vlákny. Kromě toho, Benchmark.bmbm spustí blok kódu dvakrát - poprvé za účelem zprovoznění běhového prostředí a podruhé za účelem měření. Všechny výsledky uvedené v tomto článku byly získány při druhém spuštění. Samozřejmě, že i bmbm metoda nezaručuje dokonalou izolaci, ale rozdíly mezi více spuštěnými kódy jsou zanedbatelné.

vyžadovat "benchmark"

třída Test
  AMOUNT = 4

  def run
    Benchmark.bmbm do |b|
      b.report("sequential") { sequential }
      b.report("forking") { forking }
      b.report("threading") { threading }
    end
  end

  private

  def sekvenční
    AMOUNT.times { perform }
  end

  def forking
    AMOUNT.times do
      fork do
        provést
      end
    end

    Process.waitall
  rescue NotImplementedError => e
    # metoda fork není v JRuby k dispozici
    puts e
  end

  def threading
    threads = []

    AMOUNT.times do
      threads << Thread.new do
        provést
      end
    end

    threads.map(&:join)
  end

  def perform
    raise "not implemented"
  end
end
Zátěžový test

Provádí výpočty ve smyčce a generuje tak velké zatížení procesoru.

třída LoadTest < Test
  def perform
    1000.times { 1000.times { 2**3**4 } }
  end
end

Spusťme ji...

LoadTest.new.run

...a zkontrolujte výsledky

MRIJRubyRubinius
sekvenční1.8629282.0890001.918873
rozvětvení0.945018–1.178322
závitování1.9139821.1070001.213315

Jak vidíte, výsledky sekvenčních běhů jsou podobné. Mezi řešeními je samozřejmě malý rozdíl, ale ten je způsoben základní implementací vybraných metod v různých interpretech.

V tomto příkladu má rozvětvení výrazný výkonnostní přínos (kód běží téměř dvakrát rychleji).

Vláknění poskytuje podobné výsledky jako rozvětvení, ale pouze pro JRuby a Rubinius. Spuštění ukázky s vlákny na MRI spotřebuje o něco více času než sekvenční metoda. Důvody jsou přinejmenším dva. Za prvé, GIL si vynucuje sekvenční provádění vláken, proto by v ideálním světě měla být doba provádění stejná jako u sekvenčního běhu, ale dochází také ke ztrátě času na operace GIL (přepínání mezi vlákny atd.). Za druhé, je také potřeba určitá režie času pro vytváření vláken.

Tento příklad neposkytuje nás odpověď na otázku o smyslu použití vláken v MRI. Podívejme se na další.

Test odložení

Spustí metodu spánku.

třída SnoozeTest < Test
  def perform
    sleep 1
  end
end

Zde jsou výsledky

MRIJRubyRubinius
sekvenční4.0046204.0060004.003186
rozvětvení1.022066–1.028381
závitování1.0015481.0040001.003642

Jak vidíte, každá implementace poskytuje podobné výsledky nejen při sekvenčním a vidlicovém běhu, ale také při běhu ve vláknech. Proč má tedy MRI stejný nárůst výkonu jako JRuby a Rubinius? Odpověď je v implementaci spánek.

Magnetická rezonance spánek metoda je implementována pomocí rb_thread_wait_for C, která používá další funkci s názvem native_sleep. Podívejme se na jeho implementaci (kód byl zjednodušen, původní implementaci lze nalézt na adrese zde):

static void
native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
{
  ...

  GVL_UNLOCK_BEGIN();
  {
    // udělejte zde nějaké věci
  }
  GVL_UNLOCK_END();

  thread_debug("native_sleep donen");
 }

Důvodem, proč je tato funkce důležitá, je to, že kromě použití striktního kontextu Ruby také přepíná na systémový kontext, aby v něm mohla provádět některé operace. V takových situacích nemá proces Ruby co dělat... Skvělý příklad plýtvání časem? Ne tak docela, protože existuje GIL, který říká: "V tomto vlákně není co dělat? Přepneme se do jiného a po chvíli se sem vrátíme". To by se dalo provést odemknutím a uzamknutím GIL pomocí GVL_UNLOCK_BEGIN() a GVL_UNLOCK_END() funkce.

Situace je jasná, ale spánek je zřídkakdy užitečná. Potřebujeme více příkladů z reálného života.

Test stahování souborů

Spustí proces, který stáhne a uloží soubor.

vyžadovat "net/http"

třída DownloadFileTest < Test
  def perform
    Net::HTTP.get("upload.wikimedia.org", "/wikipedia/commons/thumb/7/73/Ruby_logo.svg/2000px-Ruby_logo.svg.png")
  konec
konec

Následující výsledky není třeba komentovat. Jsou dosti podobné těm z výše uvedeného příkladu.

1.003642JRubyRubinius
sekvenční0.3279800.3340000.329353
rozvětvení0.104766–0.121054
závitování0.0857890.0940000.088490

Dalším dobrým příkladem může být proces kopírování souborů nebo jakákoli jiná I/O operace.

Závěry

  • Rubinius plně podporuje forking i threading (od verze 2.X, kdy byl odstraněn GIL). Váš kód může být souběžný a běžet paralelně.
  • JRuby dobře pracuje s vlákny, ale vůbec nepodporuje forkování. Paralelismu a souběžnosti lze dosáhnout pomocí vláken.
  • MRI podporuje rozvětvení, ale rozvětvení je omezeno přítomností GIL. Souběžnosti by bylo možné dosáhnout pomocí vláken, ale pouze v případě, že spuštěný kód jde mimo kontext interpretu Ruby (např. IO operace, funkce jádra). Neexistuje žádný způsob, jak dosáhnout paralelismu.

Související články

Ilustrace zdravotnické aplikace pro chytré telefony s ikonou srdce a rostoucím zdravotním grafem, označená logem The Codest, která představuje digitální zdraví a řešení HealthTech.
Vývoj softwaru

Softwarové vybavení pro zdravotnictví: a případy použití

Nástroje, na které se dnes zdravotnické organizace spoléhají, se v ničem nepodobají papírovým kartám z doby před desítkami let. zdravotnický software dnes podporuje zdravotnické systémy, péči o pacienty a moderní poskytování zdravotní péče v klinických a...

NEJKRÁSNĚJŠÍ
Abstraktní ilustrace klesajícího sloupcového grafu se stoupající šipkou a zlatou mincí symbolizující efektivitu nákladů nebo úspory. V levém horním rohu se zobrazuje logo The Codest se sloganem "In Code We Trust" na světle šedém pozadí.
Vývoj softwaru

Jak rozšířit tým vývojářů bez ztráty kvality produktu

Zvětšujete svůj vývojový tým? Zjistěte, jak růst, aniž byste museli obětovat kvalitu produktu. Tento průvodce se zabývá příznaky, že je čas na škálování, strukturou týmu, najímáním zaměstnanců, vedením a nástroji - a také tím, jak může The Codest...

NEJKRÁSNĚJŠÍ
Vývoj softwaru

Vytváření webových aplikací odolných vůči budoucnosti: postřehy týmu odborníků The Codest

Zjistěte, jak společnost The Codest vyniká při vytváření škálovatelných, interaktivních webových aplikací pomocí nejmodernějších technologií, které poskytují bezproblémové uživatelské prostředí na všech platformách. Zjistěte, jak naše odborné znalosti podporují digitální transformaci a obchodní...

NEJKRÁSNĚJŠÍ
Vývoj softwaru

10 nejlepších lotyšských společností zabývajících se vývojem softwaru

V našem nejnovějším článku se dozvíte o nejlepších lotyšských společnostech zabývajících se vývojem softwaru a jejich inovativních řešeních. Zjistěte, jak mohou tito technologičtí lídři pomoci pozvednout vaše podnikání.

thecodest
Podniková a škálovací řešení

Základy vývoje softwaru v jazyce Java: A Guide to Outsourcing Successfully

Prozkoumejte tuto základní příručku o úspěšném vývoji softwaru outsourcing Java, abyste zvýšili efektivitu, získali přístup k odborným znalostem a dosáhli úspěchu projektu s The Codest.

thecodest

Přihlaste se k odběru naší znalostní databáze a získejte aktuální informace o odborných znalostech z oblasti IT.

    O nás

    The Codest - Mezinárodní společnost zabývající se vývojem softwaru s technologickými centry v Polsku.

    Spojené království - ústředí

    • Kancelář 303B, 182-184 High Street North E6 2JA
      Londýn, Anglie

    Polsko - Místní technologická centra

    • Kancelářský park Fabryczna, Aleja
      Pokoju 18, 31-564 Krakov
    • Brain Embassy, Konstruktorska
      11, 02-673 Varšava, Polsko

      The Codest

    • Home
    • O nás
    • Služby
    • Case Studies
    • Vědět jak
    • Kariéra
    • Slovník

      Služby

    • To Advisory
    • Vývoj softwaru
    • Vývoj backendu
    • Vývoj frontendů
    • Staff Augmentation
    • Vývojáři backendu
    • Cloudoví inženýři
    • Datoví inženýři
    • Další
    • Inženýři QA

      Zdroje

    • Fakta a mýty o spolupráci s externím partnerem pro vývoj softwaru
    • Z USA do Evropy: Proč se americké startupy rozhodly přesídlit do Evropy?
    • Srovnání technických vývojových center v zahraničí: Tech Offshore Evropa (Polsko), ASEAN (Filipíny), Eurasie (Turecko)
    • Jaké jsou hlavní výzvy CTO a CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Copyright © 2026 by The Codest. Všechna práva vyhrazena.

    cs_CZCzech
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese es_ESSpanish nl_NLDutch etEstonian elGreek pt_PTPortuguese cs_CZCzech