Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin · Oppitunti

Samanaikaisen koodin optimointi

Opiskelkaa edistyneitä tekniikoita samanaikaisten Scala-sovellusten optimointiin, mukaan lukien säiepoolien säätäminen ja kilpailutilanteiden välttäminen.

Oppitunti 3/310 vaihetta

Samanaikaisen koodin optimointi on ilmainen Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-oppitunti CoddyKitissä. Tämä on oppitunti 3/3. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-kurssilla on yhteensä 3 oppituntia.

Miksi rinnakkaista koodia optimoidaan?

Rinnakkaisen Scala-koodin optimointi on ratkaisevan tärkeää tehokkaiden ja skaalautuvien sovellusten rakentamisessa. Tavoitteena on saada ohjelmat toimimaan nopeammin ja käsittelemään samanaikaisesti enemmän työtä.

  • Läpimeno: Kuinka monta operaatiota voidaan suorittaa aikayksikössä?
  • Viive: Kuinka kauan yhden operaation suorittaminen kestää?
  • Resurssien käyttö: Käytetäänkö suorittimen ytimiä ja muistia tehokkaasti?

Huonosti optimoitu rinnakkainen koodi voi aiheuttaa pullonkauloja, lukkiutumisia ja resurssien tehotonta käyttöä, jolloin rinnakkaisuuden hyödyt menetetään.

Säiepoolien toiminta

Säiepooli on kokoelma valmiiksi alustettuja työntekijäsäikeitä, joita voidaan käyttää uudelleen tehtävien suorittamiseen. Sen sijaan, että jokaista tehtävää varten luotaisiin uusi säie, mikä on kallista, tehtävät lähetetään pooliin.

Tämä vähentää säikeiden luomisen ja tuhoamisen aiheuttamaa kuormaa, parantaa reagointikykyä ja auttaa hallitsemaan aktiivisten säikeiden määrää resurssien loppumisen estämiseksi.

Scalan globaalin poolin määrittäminen

Scalassa asynkroniset operaatiot käyttävät usein ExecutionContext-kontekstia. Oletusarvoisesti Scala-sovellukset käyttävät globaalia ExecutionContext-kontekstia, joka on tyypillisesti ForkJoinPool.

Voitte säätää tätä oletuspoolia määrittämällä järjestelmäominaisuuksia tai yleisemmin määrittämällä dispatcher-asetuksia tiedostossa application.conf (erityisesti Akka-pohjaisissa sovelluksissa). Näin voitte hallita säikeiden määrää, work-stealing-toimintaa ja jonojen kokoja.

Yksi yleisesti säädettävä asetus on parallelism-factor, jolla poolin koko voidaan suhteuttaa käytettävissä olevien suorittimen ytimien määrään.

Mukautettujen ExecutionContext-kontekstien luominen

Vaikka globaali ExecutionContext on kätevä, eri tehtävätyypeille on usein parempi luoda mukautetut säiepoolit. Voitte esimerkiksi käyttää pientä poolia suoritinsidonnaisille tehtäville ja suurempaa poolia I/O-sidonnaisille tehtäville.

Näin hitaat I/O-operaatiot eivät estä suoritinsidonnaisia tehtäviä, mikä parantaa koko järjestelmän reagointikykyä. Näin luodaan yksinkertainen mukautettu ExecutionContext:

import java.util.concurrent.{Executors, ExecutorService}
import scala.concurrent.ExecutionContext

object CustomPoolExample {
  def main(args: Array[String]): Unit = {
    // Create a fixed thread pool with 4 threads
    val customExecutor: ExecutorService =
      Executors.newFixedThreadPool(4)

    // Wrap it in a Scala ExecutionContext
    implicit val customEC: ExecutionContext =
      ExecutionContext.fromExecutor(customExecutor)

    println("Custom ExecutionContext created.")

    // Don't forget to shut down the executor!
    customExecutor.shutdown()
  }
}

Resurssikiistan minimointi

Kiistaa syntyy, kun useat säikeet yrittävät käyttää jaettua resurssia (kuten muuttujaa, tietorakennetta tai tietokantayhteyttä) samanaikaisesti ja yhden tai useamman säikeen on odotettava.

Odottaminen aiheuttaa viivettä ja kuormaa, kun säikeet kilpailevat lukoista ja suorittimen jaksoista. Voimakas kiista voi heikentää rinnakkaisten sovellusten suorituskykyä huomattavasti, vaikka suorittimen ytimiä olisi runsaasti käytettävissä.

Kiistan vähentämiseen tähtäävät strategiat ovat olennaisia todellisen rinnakkaisuuden saavuttamisessa.

Hienojakoinen lukitus

Sen sijaan että koko olion tai suuren koodilohkon suojaamiseen käytettäisiin yhtä karkean tason lukkoa, hienojakoisessa lukituksessa käytetään pienempiä ja tarkemmin kohdistettuja lukkoja suojaamaan vain niitä tietojen osia, joita todella muokataan.

Tämä mahdollistaa olion eri osien samanaikaisen käytön eri säikeissä ja vähentää kiistaa merkittävästi. Se kuitenkin lisää monimutkaisuutta ja lukkiutumisten riskiä, jos toteutusta ei hallita huolellisesti.

class Counter {
  private var value = 0
  private val lock = new Object() // A specific lock for 'value'

  def increment(): Unit = lock.synchronized {
    value += 1
  }

  def get(): Int = lock.synchronized {
    value
  }
}

object FineGrainedLocking {
  def main(args: Array[String]): Unit = {
    val counter = new Counter()
    println(s"Initial counter value: ${counter.get()}")
    counter.increment()
    println(s"Incremented value: ${counter.get()}")
  }
}

Atomiset operaatiot suorituskyvyn parantamiseksi

Lukottomat tietorakenteet käyttävät matalan tason atomisia operaatioita (kuten Compare-And-Swap-operaatiota eli CAS-operaatiota) jaettujen muuttujien päivittämiseen ilman eksplisiittisiä lukkoja. Näin vältetään perinteisiin lukitusmekanismeihin liittyvä kuorma ja mahdollinen kiista.

Scala hyödyntää tähän Javan pakettia java.util.concurrent.atomic. Luokat, kuten AtomicInteger, AtomicLong ja AtomicReference, tarjoavat atomiset päivitykset, joten ne sopivat erityisen hyvin tilanteisiin, joissa kiistaa esiintyy paljon.

import java.util.concurrent.atomic.AtomicInteger

object AtomicCounterExample {
  def main(args: Array[String]): Unit = {
    val atomicCounter = new AtomicInteger(0)

    // Increment the counter atomically
    atomicCounter.incrementAndGet()
    println(s"Atomic counter after increment: ${atomicCounter.get()}")

    // Another atomic operation: add 5
    atomicCounter.addAndGet(5)
    println(s"Atomic counter after adding 5: ${atomicCounter.get()}")
  }
}

Mittaa suorituskyky tarkasti

Jotta voitte todella arvioida rinnakkaisten optimointien tehokkuutta, ne on mitattava tarkasti. Pelkkä ajoituksen mittaaminen System.nanoTime()-menetelmällä ei usein riitä rinnakkaiselle koodille JVM:n optimointien, lämmittelyjaksojen ja kontekstinvaihtojen vuoksi.

Ammattimaiset vertailutyökalut, kuten JMH (Java Microbenchmark Harness), on suunniteltu tähän tarkoitukseen. Ne käsittelevät JVM:n lämmittelyn ja kuolleen koodin poistamisen sekä tarjoavat tilastollisen analyysin, joten saatte luotettavat suorituskykymittarit rinnakkaisille algoritmeillenne.

Keskittykää mittareihin, kuten operaatioihin sekunnissa (läpimeno) ja keskimääräiseen suoritusaikaan (viive), vaihtelevissa kuormitustilanteissa.

Rinnakkaisuuden optimoinnin testi

Mitkä seuraavista ovat tehokkaita strategioita rinnakkaisten Scala-sovellusten optimointiin ja kiistan vähentämiseen?

Yhteenveto: parempi rinnakkaissuorituskyky

Tässä oppitunnissa tutustuimme edistyneisiin tekniikoihin rinnakkaisten Scala-sovellusten optimoimiseksi:

  • Opimme säiepoolien säätämisen tärkeyden, mukaan lukien Scalan oletusarvoisen ExecutionContext-kontekstin määrittäminen ja mukautettujen poolien luominen tiettyjä tehtävätyyppejä varten.
  • Keskustelimme kiistan välttämisen strategioista, kuten lukituksen hienojakoisuuden lisäämisestä hienojakoisella lukituksella.
  • Näimme, kuinka lukottomat tietorakenteet, erityisesti atomiset muuttujat, voivat tarjota tehokkaita ja vähän kuormaa aiheuttavia päivityksiä jaettuun tilaan.

Muistakaa aina mitata optimointienne vaikutus asianmukaisilla vertailutyökaluilla, jotta voitte varmistaa todelliset suorituskykyhyödyt!

Aloita maksutta

Opi Scala tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
39
Oppitunnit
143

Usein kysytyt kysymykset

Onko oppitunti ”Samanaikaisen koodin optimointi” ilmainen?

Kyllä – oppitunnin ”Samanaikaisen koodin optimointi” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-kurssin, päivitä CoddyKit PROhon. Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-kurssilla on yhteensä 3 oppituntia.

Mitä opin oppitunnilla ”Samanaikaisen koodin optimointi”?

Opiskelkaa edistyneitä tekniikoita samanaikaisten Scala-sovellusten optimointiin, mukaan lukien säiepoolien säätäminen ja kilpailutilanteiden välttäminen. Harjoittelet Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/3.

Kuinka kauan ”Samanaikaisen koodin optimointi”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-oppitunnilla?

Kyllä. Jokainen Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Scala-sovellusten profilointi
  2. Muistinhallinta ja GC:n säätäminen
  3. Samanaikaisen koodin optimointi
← Takaisin: Scala backend-kehitykseen ja funktionaaliseen ohjelmointiin