Kirjoittaja Aihe: Python threadid ja multicoret  (Luettu 2641 kertaa)

Ux64

  • Käyttäjä
  • Viestejä: 586
    • Profiili
Python threadid ja multicoret
« : 10.05.08 - klo:07.26 »
Miksi oheinen koodi kuormittaa prosessoria vain 35% tasolla? Mielestäni siinä on neljä erillistä threadia jotka voivat toimia vapaasti toisistaan välittämättä. Prosessorina on Q6600. Jos sitten ajankin vain yhtä threadia niin se kyllä kuormittaa yksittäisen coren tappiin. Missä tuossa koodissa on se osuus joka vaatii syknronointia? Minä en sitä siitä löytänyt ainakaan nopeasti sen tarkemmin pythonin sielunelämää tuntematta.

Ainoa juttu mikä tulee nopeasti mieleen on se että cntr olisi synkronoitu. Mutta käsittääkseni sen pitäisi olla privaatti ja funktion / blokin sisäinen muuttuja.

Koodia: [Valitse]
import threading
from time import sleep, time
 
def loop(i, event):
    while not event.isSet():
      cntr = 0
      while cntr < 1000000:
        cntr += 1     
        store='handle some data etc.'
 
event = threading.Event()

print 'starting'
 
th1 = threading.Thread(target=loop, args=(1, event))
th1.start()
th2 = threading.Thread(target=loop, args=(2, event))
th2.start()
th3 = threading.Thread(target=loop, args=(3, event))
th3.start()
th4 = threading.Thread(target=loop, args=(4, event))
th4.start()

#Lisä testi threadit kun testasin 8 threadilla, ei vaikutusta.
#th11 = threading.Thread(target=loop, args=(1, event))
#th11.start()
#th12 = threading.Thread(target=loop, args=(2, event))
#th12.start()
#th13 = threading.Thread(target=loop, args=(3, event))
#th13.start()
#th14 = threading.Thread(target=loop, args=(4, event))
#th14.start()

print 'running...'

sleep(10)

print 'stop...'

event.set()
 
th1.join()
th2.join()
th3.join()
th4.join()

print 'end'


mgronber

  • Käyttäjä
  • Viestejä: 1458
    • Profiili
Vs: Python threadid ja multicoret
« Vastaus #1 : 10.05.08 - klo:10.52 »
En hirveämmin ole Pythonia käyttänyt mutta ainakin event.isSet() vaatii käsittääkseni synkronointia.

Ux64

  • Käyttäjä
  • Viestejä: 586
    • Profiili
Vs: Python threadid ja multicoret
« Vastaus #2 : 10.05.08 - klo:11.59 »
En hirveämmin ole Pythonia käyttänyt mutta ainakin event.isSet() vaatii käsittääkseni synkronointia.

Tuota minäkin epäilin syylliseksi, siksi sinne sisälle on laitettu se miljoonan luuppi jotta tuon tarkistuksen merkitys vähenisi. Silloin kun tuolla sisälä oli pelkkä store=.... niin oisin uskonut että juuri mainitsemasi synkronoinnin vaativa event-check joka kierroksellaaiheuttaisi ongelman. Kuitenkaan tilanne ei muttunut käytännössä lainkaan lisäämällä tuo luuppi vielä tuonne sisälle.

Noissa lyhyissä tutorialeissa jotka luin jäi juuri hieman hämärän peittoon miten toimii yksityiset eritasoiset ja julkiset (globaalit) funktiot sekä muuttujat ja sykronointia ei ollut sivuttu senkään vertaa. Struktuuri taas tuli pääosin selväksi.
« Viimeksi muokattu: 10.05.08 - klo:12.02 kirjoittanut Ux64 »

Ux64

  • Käyttäjä
  • Viestejä: 586
    • Profiili
Vs: Python threadid ja multicoret
« Vastaus #3 : 17.05.08 - klo:14.08 »
Vastaus löytyi.

Onglema on siis paljon pahempaa laatua kuin epäilin. Vika ei ole koodissani vaan vika on köh, koko Pythonin toteutuksessa.

http://docs.python.org/api/threads.html


Ux64

  • Käyttäjä
  • Viestejä: 586
    • Profiili
Vs: Python threadid ja multicoret
« Vastaus #4 : 25.05.08 - klo:19.12 »
Tein sitten vastaavan testisoftan Javalla.

Lähdetään lähtökohtaisesti siitä, että java rinnastui kuten pitää ja imi kyllä kaikki coret tappiin.

Mutta sitten se seuraava kysymys olikin, kuinka ratkaisevaa suoritettava tehtävä oli suorituskyvylle.

Hyvin rinnastuvat matemaattiset tehtävät sujuivat 380% nopeammin rinnastettuna neljään threadiin kuin peräkkäin(!).

Mutta kun tehtävää muutti siten että siihen liittyi raskaita muistioperaatioita, niin suorituskyky putosi 100% tasolle vaikka kaikki coret olikin tapissa. (Eli käytännössä memory I/O bound).

Tehtävän laatu siis ratkaisee sen onko useammasta coresta hyötyä vai ei. Tämä ei liene kenellekkään yllätys. Mutta tuo oli minulle tavallaan yllätys että kun on muisti I/O:sta kyse, vaikka ei edes käytetä jaettua resurssia (samaa dataa) niin silti näillä Inteleillä suorituskyky kyykkää todella pahasti.

Voipi olla että AMD:n nelicoret muistiväylänsä ansiosta suoriutuisi paremmin noista tehtävistä.

Mainittakoon muuten että GC:llä saattaa olla myös tekemistä. Koska varasin 50 megaa muistia per threadi. Loin sitten uuden instanssin aina tuosta 50 megasta ja discardasin vanhan. Eli tehtävä oli todellakin memory i/o bound. Käytännössä oli vain marginaalinen ero sillä suoritettiinko tuo tehtävä rinnan vai sarjassa. Tietysti kun tuo uusi kopio säästettiin ja vanha hylättiin niin se työllisti myös GC:tä.

Matemaattinen tehtävä oli taas piin desimaalit, ja se sujui hienosti. Ilmeisesti kaikki tehtävän suorittamiseen tarvittava data mahtui prosessorin ytimien cacheen ja homma rullasi varsin mahtavalla suorituskyvyllä.

Tuohon välimaastoon sitten monet tehtävät menee. Esimerkiksi voisi olla mielenkiintoista testata miten paljon pakkausikkunan koko vaikuttaa esim 7-zipin kanssa. Toimiiko 7-zip multithreading paremmin pienemmällä kuin suuremmalla pakkausikkunalla? En tiedä täsmälleen mikä on noiden pakkausalgoritmien muistinkäytön määrä, mutta tuo on hyvä vertailutehtävä. Se vaatii paljon prosessointia, mutta myös muistia käytetään paljon. Ainakin siis toistuvuustaulukon osalta. Tuossa voisi löytää hauskan raja-arvon jonka jälkeen pakkaus on esim 2 kertaa hitaampaa kuin ennen tuon raja-arvon ylittymistä.
« Viimeksi muokattu: 25.05.08 - klo:19.24 kirjoittanut Ux64 »