PHP: Yüksek Performanslı Komut Dosyası Nasıl Yazılır?
Web ajansı » Dijital haberler » PHP: Yüksek Performanslı Komut Dosyası Nasıl Yazılır?

PHP: Yüksek Performanslı Komut Dosyası Nasıl Yazılır?

PHP betik benzeri bir dil olabilir ve yavaş olduğu için eleştirilebilir, ancak en yaygın kullanılan web sunucu dillerinden biri olmaya devam etmektedir. Zamanla, PHP kullanan büyük web şirketleri motoru optimize etmeye çalıştı. kavramının tanıtılması Çöp toplayıcı 5.3 sürümünde kayda değer bir ilerleme oldu. Ama bunun birçok yolu var'bir betiğin performansını optimize et.

Ağırlıklı olarak basit sayfa oluşturma çerçevesinde kullanılan bu optimizasyonlar belli bir kazanım getirebilse de kullanıcı tarafından yeterince görülmemektedir. Nginx kullanımıyla veritabanlarının, web sunucularının optimizasyonu, HHVM'nin ve hatta HippyVM'nin gelişiyle motor optimizasyonu, sayfalarınızın oluşturulmasını hızlandırmanıza ve sorgularınıza yanıt verme süresini daha basit bir şekilde optimize etmenize olanak tanır. Buna rağmen, bazen yapmak amacıyla PHP betikleri geliştiriyoruz. ağır muameleveya web sunucuları hiçbir şey yapamaz.

Bu yazıda detaylandıracağım üç optimizasyon alanı son zamanlarda büyük miktarda bilgi içeren CSV veya XLS dosyalarını işlemesi gereken bir komut dosyasına uyguladım. Kullanılan bellek miktarı endişelenmeden 1 GB'a ulaştı ve 1/2 saatten fazla sürebilir.

Size izin verebilecek üç PHP kavramını sunmadan önceyürütme süresini optimize edin Alınan bellek miktarının yanı sıra, bir X dilinden şikayet etmeden önce, betiğinizin algoritmik işleminin işlemenizin büyük bir kısmından sorumlu olduğunu bilin. C++, PHP'den çok daha hızlı olabilir, ancak C++ algoritmalarınız kötüyse, sorunlarınızı hemen çözmez.

Değişkenleri serbest bırakın, bellek tüketimini sınırlayın

PHP 5.3 yayımlanmadan önce, PHP'nin sorunu şuydu: aşırı bellek tüketimi. Ayrıca, sık sık bir PHP betiğinin bellek tüketiminin asla azaltılamayacağını duydum… Bu bir süre için doğruysa, neyse ki artık doğru değil. Bu yönetim biraz aşağıda göreceğimiz Çöp Toplayıcı kavramını kullanıyor.

İyi bir alışkanlık kayboldu...

Bazı dillerde bu zorunluydu. PHP'de bu kavram tamamen unutulmuştur! Bu küçük yerel işlev unset(),müthiş bir yardımcı program. C++'daki free() işlevine eşdeğerdir ve yeniden tahsis etmek ve bu nedenle hafızayı hemen boşalt değişken tarafından kullanılır. Değişken tamamen yok edilir. Bu başlangıçta PHP'yi kullanılmayan değişkenlerden kurtarır. Bunun, algoritmalarımızı daha iyi yapılandırmamıza yardımcı olan başka bir ilgisi daha var. Elbette, bir yöntem sona erdiğinde değişkenler otomatik olarak yeniden dağıtılır, ancak aşağıda göreceksiniz ki bu, "çöp toplayıcının" devre dışı bırakılması durumunda çalışarak veya sadece işini yaparken harcadığı zamanı optimize etmenize olanak tanır. Bu nedenle ayrıca hız açısından bir kazanç. Ve inanın bana, GC belleği boşaltmak için çok fazla kaynak tüketiyor.

Bir önceki paragrafta söylediğim gibi, PHP bir işlev veya yöntemin sonunda kullanılmayan değişkenleri kaldırır. Ancak toplu verileri işleyen bir komut dosyası söz konusu olduğunda, bir işlevin diğerlerini yönetmesi mümkündür. Bazı dillerde olduğu gibi, eğer bu bir ana fonksiyonsa, muhtemelen değişkenleri diğer fonksiyonlara aktarmadan önce fonksiyondan geri depolama eğiliminde olacaksınız. Hızlı bir şekilde büyük miktarda veri elde edebiliriz. Artık kullanılmadığı anda, onu etrafta "taşımanın" bir anlamı yoktur, yeniden tahsis ederiz.

Son zamanlarda, 15 MB'tan büyük bir dosyanın tamamını ayıkladığım bir komut dosyası yazarken, kullandıktan sonra onu sildim ve izin verdim. hafıza kazanmak !

Çöp Toplayıcıyı Anlamak

Hafıza yönetimini araştırırken bir meslektaşımın makalesine rastladım. Artık biraz eskimiş olan bu makalede, Pascal Martin artık bir yenilik olmayan Çöp Toplayıcı'yı açıklıyor.

Çöp Toplayıcı nedir?

Bilmeyenler veya daha önce duymuş ama hiç kullanma fırsatı bulamamış olanlar için Fransızca "kırıntı toplayıcı" olarak tercüme edilen Çöp Toplayıcı, düşük seviye işlevsellik X aralığında, çalışan işlemi durdurur ve hangi değişkenlerin silinmek üzere artık erişilebilir olmadığını saptamak için komut dosyası tarafından ayrılan bellekte bir tarama gerçekleştirir.

Anlamıyorum, daha önce PHP'nin bir yöntemin sonunda değişkenleri yok ettiği söylendi.
Bu tamamen doğru değil. C veya C++ (PHP'nin ebeveyni) ile aynı şekilde, bir yöntemin sonunda PHP çıkar ve nesne üzerindeki referansını kaybeder. C'de yalnızca işaretçi kavramı vardır, C++'da işaretçi ve referans kavramları bir arada bulunur.

Nesneye yapılan başvuru kaybolduğunda ve Çöp Toplayıcı başladığında, ikincisi değişkenin artık erişilebilir olmadığını belirleyecek ve onu yok edecektir.

Bu kavram, JAVA'da ve diğer daha yeni dillerde ve dolayısıyla daha yüksek düzeyde çok mevcuttur.

Çöp Toplayıcı ne getirdi?

GC, önemli geliştirme esnekliği sağladı. C'de geliştirmenin Java, PHP veya diğerlerinden daha teknik olduğu açıktır. Buna rağmen, hafıza yönetimi gibi bazı yönler artık unutulmuştur ve bazen empati kuran bizim kodumuzdur. Bu, gelişimimize esneklik getirdiyse de, programlarımızın yürütülmesini de yavaşlattı.

Bu araçlarla unutmamamız gereken şey, hafızayı her zaman bir şekilde kontrol edebileceğimizdir. İrade mi yoksa zorunluluk mu…

Son olarak, bu tür araçların çok pratik olduğunu ancak geliştiricilerin verdiği talimatların yerini alamadığını düşünüyorum. Benim açımdan, C++ kavramının shared_ptr çok daha ilgi çekicidir ve Zend bazı durumlarda bu yöntemi kullanmaya karar verirse gelecekte çok büyük performans kazanımları sunabilir.

Ve PHP'de?

PHP 5.3'ten bu yana dört işlev eklenmiştir.

  • gc_enable
  • gc_enabled
  • gc_disable
  • gc_collect_cycles
    Belgeleri okumanız için size boş zaman bırakıyorum, ancak hızlı olmak için GC'yi etkinleştirmenize, etkin olup olmadığını öğrenmenize, devre dışı bırakmanıza ve koleksiyonu manuel olarak başlatmanıza izin veriyorlar.

Pascal Martin, yukarıda bağlantısını verdiğim gönderide pil testi yaptığı bir senaryo yayınladı. GC'siz versiyonun muazzam bellek tüketimine ulaştığını, hatta sınıra ulaşıp çöktüğünü test raporunda açıkça görebiliriz.

kıyaslama

İşte yürütülen kod. Bu, Pascal Martin'in blogundan ve özellikle makalesinden alınmıştır.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
sınıf Düğüm {
halka açık $parentNode;
halka açık $childNode'lar = dizi();
işlev Düğüm() {
bu $->nodeValue = str_repeat('0123456789', 128);
}
}
işlev ilişki oluşturmak() {
$ebeveyn= yeni düğüm();
$çocuk = yeni düğüm();
$parent->childNodes[] = $child;
$child->parentNode = $parent;
}
için ($i = 0; $ ben 500000; $i++) {
createİlişki();
// Bu kısım ikinci test sırasında yürütülür.
if ($seçenekler["gc_manuel"]) {
gc_collect_cycles();
}
}

Ayrı ayrı üç test yapıyorum:

  1. Bu testi temel seçeneklerle yapıyorum. Çöp Toplayıcı etkindir ve PHP onu düzenli olarak çalıştırır. Komut dosyasının süresi var 7.55 secondes ve kullanılan hafıza ulaştı 20.98 Mo.
  2. Aynı testi Çöp Toplayıcıyı devre dışı bırakarak ve her döngü dönüşünde çağırarak gerçekleştiriyorum. Komut dosyası 3.79 saniye sürer ve kullanılan bellek en yüksek noktasına ulaştı 244.77 Ko.
  3. Çöp Toplayıcıyı devre dışı bırakarak ve asla manuel olarak toplamayarak üçüncü bir test yapıyorum. Bu nedenle bellek güçlü bir şekilde doldurulmalıdır. Komut dosyası 4.46 saniye sürer ve hafıza ulaştı 1.98 git.

Bu test ile bellek yönetiminin önemini net bir şekilde görebiliriz. En uç noktalara götürülen örneğimizde önemi açıkça görebiliriz. Bir yandan, Çöp Toplayıcı, bellek tüketimi üzerinde çok iş yapar, ancak bu, betiğin yürütülmesini yavaşlatma eğiliminde olacaktır. 1. test (GC ile) ile yönetimsiz 3. testi karşılaştırarak bunu çok iyi görebiliriz.

Performans çalışmamızın yapıldığı yer test 2'dir. Otomatik bellek yönetimi yok, bu komut dosyası içinde optimize edilmiş manuel yönetim. İşlem hızını neredeyse iki katına çıkarmayı başardık (7.55 sn / 3.79 sn = 1.99). Böylece, ayrıca belleğimizi 245 KB ile sınırladık otomatik yönetim için 21 MB'ye karşı. Bu, neredeyse 88'lik bir katsayıdır ( (20.98 * 1024) / 244.77 = 87.77).

Sonuç

Yukarıdaki örnek, bellek yönetiminin sınırlarını zorlasa da, bu test bize bunun ne kadar olabileceğini göstermeyi amaçlamaktadır. betiklerimizde bellek yönetimini incelemek önemlidir. Ödemeler bazı durumlarda etkileyici olabilir. İşlem süresi, bellek ve onunla birlikte gelen her şey kaydedilebilir.

Referansları anlama ve kullanma

Size biraz önce söylediğim gibi, PHP değişken geçişini referans olarak uygular ve size yukarıda söylediğim gibi, bu tür geçiş aşağı yukarı işaretçi ile geçişe eşdeğerdir.

  • Referansa Göre Geçişi Anlamak
  • İşaretçi geçişini anlama
    Bu önemli bir kısım, sadece PHP için değil, çünkü bu kavram çok önceleri vardı, ama BT için. Temel olarak, bir işlev bildirdiğinizde, geçiş kopyalanarak yapılır.

    // Genel kopyalama işleviyle geçiş foo($arg) {…}

    Bu ima eder bazı artılar ve eksiler kodunuza bağlı olarak. Nesne kopyalanır, bu da ayrılan belleğin geçirilen nesnenin ağırlığı kadar artacağı anlamına gelir. Bir boole geçerseniz bu saçma olabilir, ancak örneğin bir diziyi geçerseniz çok daha önemli olabilir.

1
2
3
4
5
6
7
8
9
10
11
halka açık işlev foo() {
$bir = 1;
bar($a);
kaçırmak $a; //$a 1'dir
}
halka açık işlev bar($arg) {
$arg = 2;
}

Bu durumda değerin değiştirilmediğini görüyoruz, $a değişkenini taban olarak kullanırsak ve değerine hiç dokunmak istemiyorsak bu ilginç olabilir. Burada PHP'de olmayan bir sabit değişken kavramından (const) söz edebiliriz.

1
2
3
4
5
6
7
8
9
10
11
12
halka açık işlev foo() {
$bir = 1;
$a = bar($a);
kaçırmak $a; //$a 2'dir
}
halka açık işlev bar($arg) {
$arg = 2;
dönüş $arg;
}

Eminim zaten bunun gibi yöntemler yazmışsındır. Bu durumda, açıkça bir hatadır. Elbette, sözdizimi tamamen doğrudur, ancak parametrenin kopyası için bir tahsisat yapılmış ve bir değişkenin serbest bırakılması yapılmıştır. Pahalı bellek çağrıları ve gereksiz işlem süresi. Aşağıdaki form eşdeğer ancak çok daha hızlı olacaktır.

1
2
3
4
5
6
7
8
9
10
11
halka açık işlev foo() {
$bir = 1;
bar($a);
kaçırmak $a; //$a 2'dir
}
halka açık işlev bar(&$arg) {
$arg = 2;
}

Burada tamamen aynı tedaviyi gerçekleştirdik ama bu sadece daha hızlı ve daha az tüketiyor.

Bu optimizasyonun gerçekleştirilmesi çok basittir ve hatta kodunuzun okunmasını kolaylaştırabilir. Referansla geçiş yapmayı bilmek için birkaç sözdizimi vardır.

  1. Referansa göre geçen parametre (ki az önce gördük)
  2. Referansa göre işlev dönüşü (burada ayrıntılı değil, çünkü PHP motoru bu kısmı optimize ediyor ve ikna edici bir kazanç hissetmedim)
  3. Bir değişkeni referansa göre kopyalama, çok kullanışlı değil ama müthiş. Son derece ayrıntılı olan PHP belgelerini okumanıza izin verdim. Atladığım şeyleri kolayca öğrenebilirsin 🙂

Diğer optimizasyon

Yukarıdaki üç optimizasyon sayesinde, işlemlerinizi hızlandırırken sorun yaşamazsınız. Ancak başka maddeler de var. Yapabileceğiniz farklı optimizasyonlarla ilgili ilginç makaleleri size listeliyorum.

  • PHP String Concat ve Array Implode

Sonuç

Size az önce detaylandırdığım üç bölüm, senaryolarını optimize etmek ve gelişmeleri yeniden başlatmaktan kaçınmak için benim zevkime göre iyi bir alternatif oluşturuyor. daha hızlı dil derlenmiş bir dil olarak.

Senaryolarımdan birinde bu üç geçişi yaptım ve diğer şeylerin yanı sıra, bellek tüketimini 3 azalt yaklaşık ve 2 hız artışı elde etmek.

★ ★ ★ ★ ★