Neden Bu Kadar Çok Piton Var? Bir Python Uygulama Karşılaştırması

Yayınlanan: 2022-03-11

Python inanılmaz.

Şaşırtıcı bir şekilde, bu oldukça belirsiz bir ifade. 'Python' ile ne demek istiyorum? Soyut arayüz Python'u mu kastediyorum? Ortak Python uygulaması olan CPython'u mu kastediyorum (ve benzer şekilde adlandırılmış Cython ile karıştırılmamalıdır)? Yoksa tamamen başka bir şey mi kastediyorum? Belki de dolaylı olarak Jython, IronPython veya PyPy'den bahsediyorum. Ya da belki gerçekten derinden gittim ve RPython veya RubyPython'dan bahsediyorum (ki bunlar çok, çok farklı şeyler).

Yukarıda bahsedilen teknolojiler genel olarak adlandırılmış ve yaygın olarak başvurulan olsa da, bazıları tamamen farklı amaçlara hizmet eder (veya en azından tamamen farklı şekillerde çalışır).

Python arabirimleriyle çalıştığım süre boyunca, bu .*ython araçlarından tonlarca karşılaştım. Ancak yakın zamana kadar ne olduklarını, nasıl çalıştıklarını ve neden gerekli olduklarını (kendi yöntemleriyle) anlamak için zaman ayırmadım.

Bu eğitimde, dilin geleceği olduğuna inandığım PyPy'ye kapsamlı bir giriş yaparak, sıfırdan başlayıp çeşitli Python uygulamalarını inceleyeceğim.

Her şey 'Python'un gerçekte ne olduğunu anlamakla başlar.

Makine kodu, sanal makineler ve benzerleri hakkında iyi bir anlayışınız varsa, atlamaktan çekinmeyin.

“Python yorumlanır mı yoksa derlenir mi?”

Bu, Python'a yeni başlayanlar için ortak bir kafa karışıklığı noktasıdır.

Karşılaştırma yaparken fark edilmesi gereken ilk şey 'Python'un bir arayüz olduğudur . Python'un ne yapması ve nasıl davranması gerektiğine dair bir belirtim vardır (her arayüzde olduğu gibi). Ve birden fazla uygulama var (herhangi bir arayüzde olduğu gibi).

Farkına varılması gereken ikinci şey, 'yorumlanmış' ve 'derlenmiş' öğelerin bir arabirimin değil, bir uygulamanın özellikleri olduğudur.

Yani sorunun kendisi gerçekten iyi biçimlendirilmiş değil.

Python yorumlandı mı yoksa derlendi mi? Soru gerçekten iyi biçimlendirilmemiş.

Bununla birlikte, en yaygın Python uygulaması için (CPython: C ile yazılmış, genellikle basitçe 'Python' olarak anılır ve ne hakkında konuştuğum hakkında hiçbir fikriniz yoksa kesinlikle ne kullandığınızı) söyledi, cevap: yorumlandı , bazı derleme ile. CPython, * Python kaynak kodunu bayt koduna derler ve ardından bu bayt kodunu yorumlar ve olduğu gibi yürütür.

* Not: Bu, kelimenin geleneksel anlamıyla 'derleme' değildir. Tipik olarak, 'derlemenin' yüksek seviyeli bir dil alıp onu makine koduna dönüştürmek olduğunu söyleyebiliriz. Ama bu bir tür "derleme".

Bu cevaba daha yakından bakalım, çünkü bu, yazının ilerleyen kısımlarında ortaya çıkacak bazı kavramları anlamamıza yardımcı olacaktır.

Bayt kodu ve Makine Kodu

Bayt kodu ile makine kodu (diğer adıyla yerel kod) arasındaki farkı anlamak çok önemlidir, belki de en iyi örnek şu şekildedir:

  • C, daha sonra doğrudan işlemcinizde çalıştırılan makine kodunu derler. Her talimat, CPU'nuza bir şeyleri hareket ettirmesini söyler.
  • Java, programları yürüten bir bilgisayarın bir soyutlaması olan Java Sanal Makinesi'nde (JVM) çalıştırılan bayt kodunu derler. Her talimat daha sonra bilgisayarınızla etkileşime giren JVM tarafından işlenir.

Çok kısa terimlerle: makine kodu çok daha hızlıdır, ancak bayt kodu daha taşınabilir ve güvenlidir .

Makine kodu, makinenize bağlı olarak farklı görünür, ancak bayt kodu tüm makinelerde aynı görünür. Makine kodunun kurulumunuza göre optimize edildiği söylenebilir.

CPython uygulamasına dönersek, araç zinciri süreci aşağıdaki gibidir:

  1. CPython, Python kaynak kodunuzu bayt kodunda derler.
  2. Bu bayt kodu daha sonra CPython Sanal Makinesinde yürütülür.
Yeni başlayanlar genellikle Python'un .pyc dosyaları nedeniyle derlendiğini varsayar. Bunda bazı gerçekler var: .pyc dosyası derlenmiş bayt kodudur ve daha sonra yorumlanır. Bu nedenle, Python kodunuzu daha önce çalıştırdıysanız ve .pyc dosyasını elinizin altında bulundurursanız, bayt kodunu yeniden derlemesi gerekmediğinden ikinci seferde daha hızlı çalışır.

Alternatif Sanal Makineler: Jython, IronPython ve Daha Fazlası

Daha önce de belirttiğim gibi Python'un birkaç uygulaması vardır. Yine, daha önce de belirtildiği gibi, en yaygın olanı CPython'dur, ancak bu karşılaştırma kılavuzu için bahsedilmesi gereken başkaları da vardır. Bu, C ile yazılmış ve 'varsayılan' uygulama olarak kabul edilen bir Python uygulaması.

Peki ya alternatif Python uygulamaları? Daha öne çıkanlardan biri, JVM'yi kullanan Java ile yazılmış bir Python uygulaması olan Jython'dur. CPython, CPython VM'de çalıştırmak için bayt kodu üretirken, Jython, JVM'de çalıştırmak için Java bayt kodu üretir (bu, bir Java programını derlerken üretilenle aynıdır).

Jython'un Java bayt kodunu kullanımı bu Python uygulama şemasında gösterilmektedir.

“Neden alternatif bir uygulama kullanasınız?” Diye sorabilirsiniz. Birincisi, bu farklı Python uygulamaları, farklı teknoloji yığınlarıyla güzel bir şekilde oynuyor .

CPython, Python kodunuz için C-uzantıları yazmayı çok kolaylaştırır, çünkü sonunda bir C yorumlayıcısı tarafından yürütülür. Öte yandan Jython, diğer Java programlarıyla çalışmayı çok kolaylaştırır: Herhangi bir Java sınıfını ek bir çaba harcamadan içe aktarabilir, Java sınıflarınızı Jython programlarınızdan toplayabilir ve kullanabilirsiniz. (Bir kenara: yakından düşünmediyseniz, bu gerçekten delice. Farklı dilleri karıştırıp ezebileceğiniz ve hepsini aynı maddeye kadar derleyebileceğiniz noktadayız. (Rostin'in de belirttiği gibi, programlar Fortran ve C kodunun karışımı bir süredir ortalarda. Yani, elbette, bu mutlaka yeni değil. Ama yine de harika.))

Örnek olarak, bu geçerli Jython kodudur:

 [Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51 >>> from java.util import HashSet >>> s = HashSet(5) >>> s.add("Foo") >>> s.add("Bar") >>> s [Foo, Bar]

IronPython, tamamen C# ile yazılmış ve .NET yığınını hedefleyen bir başka popüler Python uygulamasıdır. Özellikle, JVM ile karşılaştırılabilir, Microsoft'un Ortak Dil Çalışma Zamanı (CLR) olan .NET Sanal Makinesi olarak adlandırabileceğiniz şey üzerinde çalışır.

Jython : Java :: IronPython : C# diyebilirsiniz. Aynı ilgili VM'lerde çalışırlar, IronPython kodunuzdan C# sınıflarını ve Jython kodunuzdan Java sınıflarını vb. içe aktarabilirsiniz.

CPython olmayan bir Python uygulamasına hiç dokunmadan hayatta kalmak tamamen mümkündür. Ancak, çoğu teknoloji yığınınıza bağlı olan, geçiş yapmanın avantajları vardır. Çok sayıda JVM tabanlı dil mi kullanıyorsunuz? Jython senin için olabilir. .NET yığını hakkında her şey? Belki IronPython'u denemelisiniz (ve belki de zaten denemişsinizdir).

Bu Python karşılaştırma tablosu, Python uygulamaları arasındaki farkları gösterir.

Bu arada: Bu, farklı bir uygulama kullanmak için bir neden olmasa da, bu uygulamaların aslında Python kaynak kodunuza nasıl davrandıklarının ötesinde davranış bakımından farklılık gösterdiğine dikkat edin. Bununla birlikte, bu farklılıklar tipik olarak küçüktür ve bu uygulamalar aktif olarak geliştirilmekte olduğu için zamanla çözülür veya ortaya çıkar. Örneğin, IronPython varsayılan olarak Unicode dizelerini kullanır; Ancak CPython, 2.x sürümleri için varsayılan olarak ASCII'dir (ASCII olmayan karakterler için UnicodeEncodeError ile başarısız olur), ancak 3.x için varsayılan olarak Unicode dizelerini destekler.

Tam Zamanında Derleme: PyPy ve Gelecek

Yani C, Java ve C# ile yazılmış bir Python uygulamamız var. Bir sonraki mantıklı adım: Python ile yazılmış bir Python uygulaması. (Eğitimli okuyucu bunun biraz yanıltıcı olduğunu fark edecektir.)

İşte burada işler karışabilir. İlk olarak, tam zamanında (JIT) derlemeyi tartışalım.

JIT: Neden ve Nasıl

Yerel makine kodunun bayt kodundan çok daha hızlı olduğunu hatırlayın. Peki ya bayt kodlarımızdan bazılarını derleyip yerel kod olarak çalıştırabilirsek? Bayt kodunu derlemek için bir miktar bedel ödememiz gerekecekti (yani zaman), ancak sonuç daha hızlı olsaydı, bu harika olurdu! Bu, yorumlayıcıların ve derleyicilerin faydalarını karıştıran hibrit bir teknik olan JIT derlemesinin motivasyonudur. Temel olarak, JIT, yorumlanmış bir sistemi hızlandırmak için derlemeyi kullanmak istiyor.

Örneğin, JIT'ler tarafından benimsenen ortak bir yaklaşım:

  1. Sıkça yürütülen bayt kodunu tanımlayın.
  2. Yerel makine koduna göre derleyin.
  3. Sonucu önbelleğe alın.
  4. Aynı bayt kodu çalıştırılmak üzere ayarlandığında, bunun yerine önceden derlenmiş makine kodunu alın ve avantajlardan yararlanın (yani hız artışları).

PyPy uygulamasının konusu budur: JIT'i Python'a getirmek (önceki çabalar için Ek'e bakın). Elbette başka hedefler de var: PyPy, platformlar arası, hafif bellek ve yığınsız destekleyici olmayı hedefliyor. Ancak JIT gerçekten onun satış noktasıdır. Bir sürü zaman testinin ortalaması olarak, performansı 6,27 kat artırdığı söyleniyor. Bir döküm için PyPy Speed ​​Center'daki şu tabloya bakın:

PyPy uygulamasını kullanarak JIT'i Python arayüzüne getirmek, performans iyileştirmelerinde karşılığını verir.

PyPy'yi Anlamak Zor

PyPy çok büyük bir potansiyele sahiptir ve bu noktada CPython ile oldukça uyumludur (böylece Flask, Django, vb. çalıştırabilir).

Ancak PyPy ile ilgili çok fazla kafa karışıklığı var (örneğin, bir PyPyPy oluşturmak için bu saçma teklife bakın…). Benim düşünceme göre, bunun temel nedeni PyPy'nin aslında iki şey olmasıdır:

  1. RPython'da yazılmış bir Python yorumlayıcısı (Python değil (daha önce yalan söyledim)). RPython, statik yazarak Python'un bir alt kümesidir. Python'da, türler hakkında kesin olarak akıl yürütmek "çoğunlukla imkansızdır" (Neden bu kadar zor? Şu gerçeği bir düşünün:

     x = random.choice([1, "foo"])

    geçerli Python kodu olurdu (Ademan'a kredi). x türü nedir? Türler tam olarak uygulanmadığında bile değişken türleri hakkında nasıl akıl yürütebiliriz?). RPython ile biraz esneklikten fedakarlık edersiniz, ancak bunun yerine bellek yönetimi ve daha fazlası hakkında akıl yürütmeyi çok, çok daha kolay hale getirirsiniz, bu da optimizasyonlara izin verir.

  2. Çeşitli hedefler için RPython kodunu derleyen ve JIT'e ekleyen bir derleyici. Varsayılan platform C'dir, yani bir RPython-to-C derleyicisidir, ancak JVM'yi ve diğerlerini de hedefleyebilirsiniz.

Yalnızca bu Python karşılaştırma kılavuzunda netlik sağlamak için bunlara PyPy (1) ve PyPy (2) olarak değineceğim.

Bu iki şeye neden ihtiyaç duyasınız ve neden aynı çatı altında? Şöyle düşünün: PyPy (1), RPython ile yazılmış bir yorumlayıcıdır. Böylece kullanıcının Python kodunu alır ve onu bytecode olarak derler. Ancak yorumlayıcının kendisi (RPython'da yazılmıştır) çalışabilmesi için başka bir Python uygulaması tarafından yorumlanmalıdır, değil mi?

Eh, yorumlayıcıyı çalıştırmak için sadece CPython kullanabiliriz. Ama bu çok hızlı olmayacaktı.

Bunun yerine, fikir şudur: PyPy'nin yorumlayıcısını başka bir platformun (örneğin, C, JVM veya CLI) koduna göre derlemek için PyPy (2) (RPython Araç Zinciri olarak anılır) kullanıyoruz ve JIT'i şu şekilde ekleyerek: kuyu. Sihirlidir: PyPy dinamik olarak JIT'i bir yorumlayıcıya ekleyerek kendi derleyicisini oluşturur! ( Yine, bu delice: başka bir ayrı, bağımsız derleyici ekleyerek bir yorumlayıcı derliyoruz. )

Sonuç olarak, Python kaynak kodunu yorumlayan ve JIT optimizasyonlarından yararlanan bağımsız bir yürütülebilir dosya ortaya çıkıyor. Bu da bizim istediğimiz şeydi! Bir ağız dolusu, ama belki bu şema yardımcı olabilir:

Bu diyagram, bir yorumlayıcı, derleyici ve JIT ile bir yürütülebilir dosya dahil olmak üzere PyPy uygulamasının güzelliğini göstermektedir.

Tekrarlamak gerekirse, PyPy'nin gerçek güzelliği, JIT hakkında endişelenmeden RPython'da kendimize bir sürü farklı Python yorumlayıcısı yazabilmemizdir. PyPy daha sonra RPython Toolchain/PyPy (2) kullanarak bizim için JIT uygular .

Aslında, daha da soyut olursak, teorik olarak herhangi bir dil için bir tercüman yazabilir, onu PyPy'ye besleyebilir ve o dil için bir JIT alabilirsiniz. Bunun nedeni, PyPy'nin yorumladığı dilin ayrıntılarından ziyade gerçek tercümanı optimize etmeye odaklanmasıdır.

Teorik olarak herhangi bir dil için bir tercüman yazabilir, onu PyPy'ye besleyebilir ve o dil için bir JIT alabilirsiniz.

Kısa bir arasöz olarak, JIT'in kendisinin kesinlikle büyüleyici olduğunu belirtmek isterim. Aşağıdaki gibi yürütülen izleme adı verilen bir teknik kullanır:

  1. Yorumlayıcıyı çalıştırın ve her şeyi yorumlayın (JIT eklemeden).
  2. Yorumlanan kodun hafif bir profilini yapın.
  3. Daha önce gerçekleştirdiğiniz işlemleri tanımlayın.
  4. Bu kod parçalarını makine koduna kadar derleyin.

Daha fazlası için, bu makale oldukça erişilebilir ve çok ilginç.

Özetlemek gerekirse: PyPy'nin RPython tarafından uygulanan yorumlayıcısını derlemek için PyPy'nin RPython-to-C (veya diğer hedef platform) derleyicisini kullanıyoruz.

Toplama

Python uygulamalarının uzun bir karşılaştırmasından sonra kendime şunu sormam gerekiyor: Bu neden bu kadar harika? Bu çılgın fikir neden peşinden gitmeye değer? Alex Gaynor'un blogunda bunu iyi ifade ettiğini düşünüyorum: “[PyPy gelecek] çünkü [o] daha iyi hız, daha fazla esneklik sunuyor ve Python'un büyümesi için daha iyi bir platform.”

Kısacası:

  • Kaynak kodunu yerel kodla (JIT kullanarak) derlediği için hızlıdır .
  • Esnektir çünkü çok az ek çalışmayla JIT'i tercümanınıza ekler .
  • Esnektir (yine) çünkü tercümanlarınızı RPython'da yazabilirsiniz , bu da genişletilmesi örneğin C'den daha kolaydır (aslında, kendi tercümanlarınızı yazmak için bir öğretici olması o kadar kolaydır).

Ek: Duymuş Olabileceğiniz Diğer Python İsimleri

  • Python 3000 (Py3k): 2008'de sahneye çıkan büyük, geriye dönük uyumsuz bir Python sürümü olan Python 3.0 için alternatif bir adlandırma. Py3k ekibi, bu yeni sürümün tamamen benimsenmesinin yaklaşık beş yıl süreceğini tahmin ediyordu. Ve çoğu (uyarı: anekdot iddiası) Python geliştiricileri Python 2.x'i kullanmaya devam ederken, insanlar giderek Py3k'nin bilincine varıyor.

  • Cython: C işlevlerini çağırmak için bağlamaları içeren bir Python üst kümesi.
    • Hedef: Python kodunuz için C uzantıları yazmanıza izin verin.
    • Ayrıca, mevcut Python kodunuza statik yazma eklemenize, derlenmesine ve C benzeri performansa erişmenize olanak tanır.
    • Bu, PyPy'ye benzer, ancak aynı değil. Bu durumda, bir derleyiciye iletmeden önce kullanıcı kodunu yazmaya zorluyorsunuz. PyPy ile düz eski Python yazarsınız ve derleyici her türlü optimizasyonu gerçekleştirir.

  • Numba: Açıklamalı Python koduna JIT ekleyen "tam zamanında uzmanlaşmış bir derleyici". En temel terimlerle, ona bazı ipuçları verirsiniz ve kodunuzun bölümlerini hızlandırır. Numba, veri analizi ve yönetimi için bir dizi paket olan Anaconda dağıtımının bir parçası olarak gelir.

  • IPython: tartışılan her şeyden çok farklı. Python için bir bilgi işlem ortamı. GUI araç takımları ve tarayıcı deneyimi vb. desteğiyle etkileşimli.

  • Psyco: bir Python genişletme modülü ve ilk Python JIT çabalarından biri. Ancak, o zamandan beri “bakımsız ve ölü” olarak işaretlendi. Aslında, Psyco'nun baş geliştiricisi Armin Rigo, şimdi PyPy üzerinde çalışıyor.

Python Dil Bağlantıları

  • RubyPython: Ruby ve Python VM'leri arasında bir köprü. Python kodunu Ruby kodunuza gömmenizi sağlar. Python'un nerede başlayıp nerede durduğunu tanımlarsınız ve RubyPython verileri VM'ler arasında sıralar.

  • PyObjc: Python ve Objective-C arasındaki dil bağlantıları, aralarında bir köprü görevi görür. Pratik olarak bu, Python kodunuzdaki Objective-C kitaplıklarını (OS X uygulamaları oluşturmak için ihtiyacınız olan her şey dahil) ve Objective-C kodunuzdaki Python modüllerini kullanabileceğiniz anlamına gelir. Bu durumda, CPython'un Objective-C'nin bir alt kümesi olan C ile yazılması uygundur.

  • PyQt: PyObjc size OS X GUI bileşenleri için bağlama sağlarken, PyQt Qt uygulama çerçevesi için aynı şeyi yaparak zengin grafik arayüzleri oluşturmanıza, SQL veritabanlarına erişmenize vb. izin verir. Python'un basitliğini diğer çerçevelere getirmeyi amaçlayan başka bir araç.

JavaScript Çerçeveleri

  • pyjs (Pijama): Python'da web ve masaüstü uygulamaları oluşturmak için bir çerçeve. Bir Python-JavaScript derleyicisi, bir pencere öğesi seti ve birkaç araç daha içerir.

  • Brython: Py3k kodunun tarayıcıda yürütülmesine izin vermek için JavaScript ile yazılmış bir Python VM.