A Python atyja, Guido van Rossum a továbbiakban nem vesz részt a nyelv fejlesztésére vonatkozó döntéshozatali eljárásokban. Ezt a python-committers levelezési listán jelentette be. Elfáradt, és egészségügyi problémákra is hivatkozik, de úgy tűnik, hogy különösen megviselte a PEP 572 érdekében vívott harc is.
Minden tisztelet megilleti az eddig végzett munkájáért. A PEP 572-ben egy olyan újítás van megfogalmazva, a "nevesített kifejezések" néven, amelyeket személy szerint nagyon hiányoltam a Pythonból, mert a C-ben gyakran használtam a hasonló konstrukciót. Egy példa:
stuff = [ (y := f(x), x/y) for x in range(5)]
Ahelyett, hogy kétszer számoltatnánk ki az f(x)-et:
stuff = [ (f(x), x/f(x)) for x in range(5)]
- 6396 megtekintés
Hozzászólások
:(
-----
„Egy jó kapcsolatban a társunkat az ő dolgában kell támogatni, nem a miénkben.”
rand() a lelke mindennek! :)
Szerinted…
- A hozzászóláshoz be kell jelentkezni
Én másodszorra úgy olvastam, hogy Guido van rosszul. :(
- A hozzászóláshoz be kell jelentkezni
Stílszerűbb lett volna 1,5 év múlva:
https://pythonclock.org/
Akkor még van 1,5 év, hogy a 3-as is legalább ugyanolyan gyors (lassú) legyen, mint a 2-es. :)
- A hozzászóláshoz be kell jelentkezni
Csak Lennart Pöttering ne tudja meg...
--
robyboy
- A hozzászóláshoz be kell jelentkezni
Mr Poetsch nem venné észre az analógiát :D
- A hozzászóláshoz be kell jelentkezni
Nem vagyok egy python guru, de a fenti problémára több alternatíva is kínálkozik. Persze az is igaz, hogy a nevesített kifejezés rövidebb.
- A hozzászóláshoz be kell jelentkezni
Persze az is igaz, hogy a nevesített kifejezés rövidebb.
Pont ez volt a cél. ;-)
- A hozzászóláshoz be kell jelentkezni
Normálisan ilyenkor az következne, hogy valaki beindítja a Python4-et, ügyelve arra, hogy ne legyen kompatibilis egyik meglévővel sem.
- A hozzászóláshoz be kell jelentkezni
Ugye nem pályázol a helyére?:-)
--
eutlantis
- A hozzászóláshoz be kell jelentkezni
Angular már 6-nál jár, bele kéne húzni XD
- A hozzászóláshoz be kell jelentkezni
Vagy forkoljak Snake neven, es a fejlesztesere letrehoznak egy ceget, mondjuk Snakeoil Ltd. neven.
--
When you tear out a man's tongue, you are not proving him a liar, you're only telling the world that you fear what he might say. -George R.R. Martin
- A hozzászóláshoz be kell jelentkezni
Ezt eddig is megtehették volna. Amúgy volt már ilyenre példa és pozitív hatása volt: http://anandmanisankar.com/posts/nodejs-iojs-why-the-fork/
- A hozzászóláshoz be kell jelentkezni
Akkor már lehetőleg Snake és Snake3 néven forkoljanak, gondosan ügyelve, hogy ne lehessen a legrövidebb scriptet se úgy megcsinálni, hogy mindkettővel menjen.
- A hozzászóláshoz be kell jelentkezni
Minek forkolni?
Elegendő az ECMAScript 6-ot vagy a PHP7-et átnevezni Snake4-re:-)
--
eutlantis
- A hozzászóláshoz be kell jelentkezni
https://www.urbandictionary.com/define.php?term=snake%20oil
--
When you tear out a man's tongue, you are not proving him a liar, you're only telling the world that you fear what he might say. -George R.R. Martin
- A hozzászóláshoz be kell jelentkezni
mwhaha. azert elvarnam egy modern forditotol, hogy a fenti kifejezest kioptimalizalja maga, no es persze rogton tovabbforditsa gepi kodra.
Sajna ezt egyelore egyetlen fordito kepes megcsinalni kovetkezetesen es megbizhatoan, es az a jvm. talan meg a .net-nek van valami hasznalhato jit-je, de ennyi. ez gaz.
- A hozzászóláshoz be kell jelentkezni
Szerintem nem csak az optimalizációval van gond, hanem a kódduplikációval is.
Leteszteltem a lehetséges python jittereket az alábbi kóddal:
import time, re
def f(x):
back = []
for i in range(0,x):
if i not in back:
back.append(i)
return back[1:10]
s = time.time()
back = f(20000).index(1)
print("Indexing one", time.time() - s)
s = time.time()
back = f(20000).index(1) + f(20000).index(2)
print("Indexing two", time.time() - s)
pattern = "[A]+" * 12
test_str = "A" * 1000
s = time.time()
[len(re.match(pattern, test_str).group(0)) for i in range(1000)]
print("Matching one", time.time() - s)
s = time.time()
[len(re.match(pattern, test_str).group(0)) for i in range(1000) if re.match(pattern, test_str)]
print("Matching two", time.time() - s)
CPython2
('Indexing one', 1.9690001010894775)
('Indexing two', 3.921999931335449)
('Matching one', 0.05299997329711914)
('Matching two', 0.0969998836517334)
Pypy2 6.0.0
('Indexing one', 0.05799984931945801)
('Indexing two', 0.11500000953674316)
('Matching one', 0.07500004768371582)
('Matching two', 0.10299992561340332)
IronPython + .net4.5
('Indexing one', 4.1027679443359375)
('Indexing two', 8.1740570068359375)
('Matching one', 0.07904052734375)
('Matching two', 0.14720916748046875)
IronPython + .netcore2.0
('Indexing one', 3.7830429077148438)
('Indexing two', 7.5531768798828125)
('Matching one', 0.09737396240234375)
('Matching two', 0.16550445556640625)
Python 3.6 + numba
Indexing one 0.2415463924407959
Indexing two 0.16579389572143555
Matching one 0.07383203506469727
Matching two 0.08798456192016602
Szóval a numba-n kívül a többi nem végzett ilyen jellegű optimalizációt. (.net esetében lehet, hogy az ironpython implementáció miatt)
Érdekességképpen megnéztem javascripttel is:
Chrome
Indexing one: 221.033935546875ms
Indexing two: 437.77392578125ms
Firefox
Indexing one: 184ms
Indexing two: 352ms
Edge
Indexing one: 103,225ms
Indexing two: 202,515ms
- A hozzászóláshoz be kell jelentkezni
És ha kioptimalizánánk az ismétlődő függvényhívásokat, akkor pl. a "print('hello\n')" vagy a "random(6)" második hívását is ki lehetne hagyni, vagy azért valahogy felismernénk, hogy a függvénynek van mellékhatása, és/vagy nem-determinisztikus?
- A hozzászóláshoz be kell jelentkezni
Lefuttattam újra a tesztet és rájöttem, hogy fals eredményeket kaptam numba-val: a
f(20000).index(1) + f(20000).index(2)
csak a jit warmup miatt volt gyorsabb, mint a
f(20000).index(1)
futása. Új eredmények numba-val:
Indexing one 0.2547800540924072
Indexing one for second time 0.0816488265991211
Indexing two 0.19306492805480957
Indexing three 0.24411439895629883
Matching one 0.07869338989257812
Matching one second time 0.045740365982055664
Matching two 0.09146356582641602
Matching three 0.1360464096069336
Szóval egyik általam tesztelt jitter sem végzett ilyen jellegű optimalizálást
- A hozzászóláshoz be kell jelentkezni
Haha, ez jo, megcsinaltam ugyanezt java + jmh -val:
public static int[] f2(int x) {
int[] back = new int[x];
int backi = 0;
for (int i = 0; i < x; i++)
if (!ArrayUtils.contains(back, i)) back[backi++] = i;
return ArrayUtils.subarray(back, 0, 10);
}
@Benchmark
public void one2() {
res = f2(20000)[0];
}
@Benchmark
public void two2() {
res = f2(20000)[0] + f2(20000)[1];
}
eredmeny (1 core, 1 thread, egy 2014-es macbookon):
# Run complete. Total time: 00:01:24
Benchmark Mode Cnt Score Error Units
VsPython.one2 thrpt 20 11.675 ± 0.228 ops/s
VsPython.two2 thrpt 20 5.735 ± 0.178 ops/s
Egyebkent IMHO logikus elvaras, hogy a fordito tudja/sejtse elore, ha egy metodus nem modosit allapotot (es ezen felul meg lehessen explicite mondani), es aszerint optimalizalja az ismetlodo hivasokat.
Valszeg megneztek ezt, BTW, csak a gyakorlatban eleg maceras ilyet stabilra megcsinalni, keves helyen lehet hasznalni, ott meg eccerubb megcsinalni kezzel.
De ez a pypy2 igen erosre sikerult! Eddig mindenhol azt lattam, hogy meg ha van is JIT, doglassu (lasd .net). Felteszem okkal nem hasznalja ezt mindenki, csak nem tudom, mi az :)
PS: teljes kod elerheto: https://github.com/agoston/benchmark/blob/master/src/test/java/com/bol/…
- A hozzászóláshoz be kell jelentkezni
> De ez a pypy2 igen erosre sikerult! Eddig mindenhol azt lattam, hogy meg ha van is JIT, doglassu (lasd .net). Felteszem okkal nem hasznalja ezt mindenki, csak nem tudom, mi az :)
C-ben írt modul inkompatibilitások/lassulások, illetve (mint általában minden JIT) több memóriát eszik, mint az alap Python. A fenti kód Win10-en: CPython: 4MB, Pypy: 25MB, Numba: 82MB (update: ebből a szempontból valószínű nem mérvadó a teszt, mert egy üres script is kb ennyit eszik)
- A hozzászóláshoz be kell jelentkezni
Nem feltétlenül ekvivalens a kettő, ha f(x)-nek side effectje van, akkor egyáltalán nem mindegy, hogy kétszer, vagy egyszer értékeled ki. Például ha f(x) nyilvántartja meghívásainak számát egy adatmezőben, akkor baromira nem ugyanaz lesz a két kiértékelés eredménye.
- A hozzászóláshoz be kell jelentkezni
De hát pont erről van szó, hogy a fordító tudHATná, hogy pure function-ről van-e szó, van-e mellékhatása, és ha nincs, akkor optimalizálja ki.
Amúgy azt olvastam, hogy ha a függvény elég kicsi, akkor inline-olásra kerül, és akkor már lehet, hogy nem lesz kétszer "meghívva".
- A hozzászóláshoz be kell jelentkezni
De ha kétszer van inline-olva, akkor megint csak kétszer hajdótik végre a side effect. Amúgy azt megállapítani, hogy valami biztosan pure function, ekivalens a halting problemmel, általánosan nem megoldható. Szóval nem, a fordító ezt nem tudhatná biztosan sosem. És ez bizonyítható :)
- A hozzászóláshoz be kell jelentkezni
Akkor nem írtam volna, amit írtam. Azt olvastam, hogy ha inline-olásra kerül a dupla függvényhívás, akkor már ki lesz optimalizálva, mert metóduson belül a JIT már látja, hogy fölösleges valamit újra meghívni. Itt olvastam, persze lehet, hogy félreértettem, mert nem ismerem a Hotspot legmélyebb titkait: https://stackoverflow.com/a/48050831/552139 és https://stackoverflow.com/a/48047090/552139 .
Managed programnyelvekben (pl. Java) elég könnyen megállapítható a dolog. Ha a függvény csak a bemeneti paramétereivel dolgozik (nem ír és nem olvas globális állapotot, nincs I/O, nincs szálkezelés és locking és stb.), és azok immutable típusok, akkor az egy pure function.
public static int add(int a, int b) { return a + b; }
Szerinted mennyire nehéz erről megállapítani, hogy pure function? A kritériumok, amiket fentebb írtam, mindegyik elég könnyen ellenőrizhető. Az más tészta, hogy egyes típusok kieshetnek a túl szigorú szűrés miatt (pl. com.google.common.collect.ImmutableList módosítható, de kizárólag reflection-nel).
- A hozzászóláshoz be kell jelentkezni
A kérdésben teljesen mindegy, hogy managed, vagy nem managed, nem a memórikezelés módja dönti el azt, hogy egy függvény pure-e vagy nem :)
"Ha a függvény csak a bemeneti paramétereivel dolgozik, és azok immutable típusok, akkor az egy pure function"
Na, ez nem igaz.
public static void foo(final Foo param) {
param.doStuff();
}
ahol Foo:
public class Foo() {
private final MySingleton singleton;
public Foo(MySingleton singleton) {
this.singleton = singleton;
}
public void doStuff() {
singleton.doSideEffect();
}
}
Foo egy tökéletes immutable osztály. MySingleton attól singleton, hogy egy DI container egyet hoz belőle létre (és nem azért, mert GoF szerinti Singleton).
A foo metódus csak a bemenetként kapott osztállyal dolgozik. Mégis van side effect.
Amit akartál mondani, hogy a bemenetek value classok (minden value class immutable, de nem minden immutable value class).
Szóval még mindig nem triviális probléma ez :)
- A hozzászóláshoz be kell jelentkezni
Azt hittem, hogy nyilvánvaló, de álljon itt: egy function nem lehet pure, ha hív olyat, ami nem pure. Semmivel sem bonyolultabb ennek a megállapítása, mint az eddigiek. Így mit szólsz hozzá?
- A hozzászóláshoz be kell jelentkezni
"egy function nem lehet pure, ha hív olyat, ami nem pure. Semmivel sem bonyolultabb ennek a megállapítása, mint az eddigiek. "
Dehogynem bonyolultabb.
Tegyük fel, hogy a függvényed bemenő argumentuma egy interfész. Nem tudhatod, hogy az implementáció, ami oda megy, pure lesz-e, vagy nem.
Honnan tudod, hogy olyat hív, ami pure, vagy nem? Azt sem tudod, milyen implementáció megy oda be.
Nagyon-nagyon-nagyon szűk azon kódok köre, aminél meg lehet mondani, hogy egy függvény tényleg pure-e (mert mint mondtam, ez ekvivalens a halting problemmel).
- A hozzászóláshoz be kell jelentkezni
Egy adott JVM processzben egy interfész összes implementációja ismert és alacsony számosságú. A CHA optimalizáció használja is ezt az infót. Avval persze egyet értek, hogy a kör szűk, valószínűleg ezért is nem támogatja direktben a Hotspot.
- A hozzászóláshoz be kell jelentkezni
Dinamikus osztálybetöltésről még nem hallottál? Runtime bytekód manipulációról még nem halottál?
Compile time baromira nem ismert a runtime minden osztálya. És az, hogy inline-olsz-e valamit, az compile time döntés.
- A hozzászóláshoz be kell jelentkezni
> És az, hogy inline-olsz-e valamit, az compile time döntés.
JVMről, JITről szól még mindig ez a szál, vagy valahol váltás volt időközben?
- A hozzászóláshoz be kell jelentkezni
Compilerről beszéltünk. Az, hogy ez mikor fut (AOT vagy JIT), totál más kérdés. Amit a C1/C2 JIT fordít valamit vagy a Graal AOT fordít valamit, és inline mellett dönt, az egy compile döntés.
Az egy dolog, hogy a C2 JIT a compile döntését profilozás alapján hozza meg, az AOT meg nem. De nem a runtime mondja meg a compilernek, hogy itt inline-olnod kell (a runtime nem tudja utasítani a compilert), a compiler dönt. Nincs inline kulcsszó, ahol te vezérled a compilert, és fejlesztési időben hozol döntést. Vagy épp a futó C1/C2 compilationt sem tudod vezérelni, hogy mi az, amit mindenképp inline-oljon, mert te tudod, hogy az jó lesz. Java esetén az inlineolás mindig compile time döntés, amit a compiler a rendelkezésére álló információk alapján hoz meg (ezért sincs például Graal AOT estén dynamic classloading támogatva). C1/C2 esetén rendelkezésére áll futási profil. De amint az változhat (mert classload van), akkor egyből jön az, hogy az addigi eredményt eldobja.
Nem tudod a compilert befolyásolni kívülről. Majd ő dönt, amikor compile van.
És amikor futásidőben hoz döntést a C1/C2, az csak bizonyos esetekben jó.
Monomorf esetekben nagyon jó, polimorf esetekben nem annyira jó. Pont azért, mert elvileg sem lehet annyira jó. Persze, lehet isteníteni ezeket a compilereket, de a CHA/devirtualization/profilin nem mindenható ám :)
- A hozzászóláshoz be kell jelentkezni
de akkor, adott példában mégiscsak tudja a C2, hogy az XYZ interfészből hány implementáció van betöltve. classloadkor deop meg most is van.
tehát még mindig ott járunk, ahonnan kiindultunk: a fordító tudHATná, hogy egy f(x) függvényhívás biztosan pure.
- A hozzászóláshoz be kell jelentkezni
Azt, hogy valami biztosan pure, már elméletileg sem tudhatja *minden esetben. Azaz akkor is, ha minden osztályt ismered, ami be van töltve, minden interfész minden implementációja fix, akkor sem tudod mindig eldönteni, hogy valami biztosan pure. Ugyanis ez ekvivalens a halting problemmel. Nem tudsz olyan kódot írni, ami mindig, minden esetben megmondja, hogy "f pure function".
- A hozzászóláshoz be kell jelentkezni
Oké, de a kicsit gyengébb megfogalmazás is hasznos tud lenni: egyik kimenet, hogy biztosan pure, a másik kimenet, hogy passz. Ha nincsenek benne egyáltalán azok a dolgok, amiket fent írtam (pl. I/O, metóduson kívüli állapot írása/olvasása, stb.), akkor nagyon könnyű eldönteni, hogy pure (pl. az "int add(int,int)" metódusról simán látjuk, hogy az). Ha ez nem igaz rá, akkor még mindig lehet, hogy pure, de valószínűleg inkább nem az, akkor mondjuk rá azt, hogy passz, és kész. Amikor már olyan szinten bizonytalan a dolog, hogy pl. muszáj minden létező bemenetre leszimulálni a függvényt, és abból talán kijön, hogy ez bizony minden bemenetre pure volt, az tényleg halting problem, de nyilván ilyen szintre semmilyen fordító nem megy el, semmilyen más optimalizáció során sem, csak az egyszerűbb és igazolhatóan korrekt esetekben végeznek el transzformációkat.
- A hozzászóláshoz be kell jelentkezni
Én már nagyon sok mindenről hallottam, de te hallottál-e arról, hogy a CHA miből és hogyan dolgozik?
- A hozzászóláshoz be kell jelentkezni
Persze. És amint dynamic classload van, a CHA újra elvégződik, ez tök alap dolog, azt hiszem 2 vagy 3 éve tartott a JVM Language Summiton az egyik Azul fejlesztő erről egy nagyon jó előadást. Amint classload van, a devirtualizálás eldobódik.
A CHA egy heurisztika csak, ami a monomorf eseteket kezeli nagyon jól, a polimorf eseteket kevésbé jól. És sokszor el is dobják az eredményét, csak tényleg a hot codepath az, ahol működik.
Na jó, amúgy lelövöm a poént: azért írtam pont az interfészes példát pár kommenttel feljebb, mert interfészre nincs CHA.
https://youtu.be/E9i9NJeXGmM?t=1h11m43s
- A hozzászóláshoz be kell jelentkezni
Java esetén: abszolúte tévedsz.
java compile esetén _nincs_ optimalizáció, hogy minden platform ugyanazt a class-t lássa. Ezért tudsz decompile-olni szinte szó szerint forrással egyezőre.
Mindig, MINDIG a jit optimalizál, futás közben, folyamatosan. Ha reflectionnel belenyúsz a pl. add metódusba (a példa fentebb valahol), újrafordítja és újraoptimalizálja az érintett metódusokat.
minek olvass utána: "HotSpot" compiler
- A hozzászóláshoz be kell jelentkezni
Mindvégig HotSpot C1/C2-ről beszéltünk, nem a javacról. Másról nincs értelme, inlining javacban nincs is.
- A hozzászóláshoz be kell jelentkezni
Pont ezért nem értem, miről beszéltél.
- A hozzászóláshoz be kell jelentkezni
Nem tokeletes a dolog, de C-ben pl. van volatile, direkt arra, hogy ne optimalizaljon ki a fordito olyat, ami mashogy (pl. interruptbol) is valtozhat.
Illetve Postgresql-ben vannak olyan tarolt eljarasok, amikre megadhatod, hogy ez itt mindig ugyanazt adja mellekhatas nelkul, es kioptimalizalhato.
--
When you tear out a man's tongue, you are not proving him a liar, you're only telling the world that you fear what he might say. -George R.R. Martin
- A hozzászóláshoz be kell jelentkezni
Jo; lehet, hogy felszabadultabba valik a fejlodes.
Jon a Microsoft, es jot tesz majd.
- A hozzászóláshoz be kell jelentkezni
Eddig is ott voltak. https://blogs.msdn.microsoft.com/pythonengineering/2018/05/31/recap-mic…
--
♙♘♗♖♕♔
- A hozzászóláshoz be kell jelentkezni