Winuser's Blog

18 listopada 2010

C++ kontra PHP

Filed under: C++,PHP,Programowanie,Projekty,WWW — winuser @ 9:42
Tags: , , , , ,

Tak jak ostatnio obiecałem, tak oto zamieszczam moje przemyślenia / badania kwesti wydajności programów kompilowanych (C++) oraz skryptów (PHP). Jest sprawą oczywistą że walka jest nierówna, że porównanie może nie mieć sensu, że te języki stworzono do innych zadań. Ale olejmy na chwilę te wszystkie gadki, jak naprawdę przekłada się to co mówią ludzie na prawdziwe pomiary ? Sprawdziłem to i w tym wpisie można przeczytać efekty tego. Zamieszczam również kod klasy C++ do mierzenia czasu wykonania funkcji czy bloku programu. Zasady sprawdzania były proste, postawiony serwer www z użyciem popularnego pakietu WebServ (do testowania skryptu PHP) oraz skompilowany program C++ (użyłem kompilatora G++) w wersji release wrzucony do folderu CGI-BIN, odpalany z poziomu przeglądarki internetowej Opera. Na pierwszy ogień poszła konktatencja napisów. Żeby walka była wyrównana (zresztą nie może i tak być o wyrównanej walce mowy), to w kodzie C++ użyłem klasy std::string zamiast zwykłych wskaźników char, bo wynik mógłby się okazać wręcz miażdżący dla PHP. Niestety nawet mimo tego się taki okazał.. Wynik PHP: ~27 sekund, wynik C++: ~1.8 sekundy. Kod programu C++ :

#include <iostream>
#include <string>

#include "PerformanceTimer.h"

using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	string napis;
	
	pt.Start();
	for (int i = 0; i < 100000000; i++)
	{
		napis += i;
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double)10000000) << endl;
	cout << "</body></html>";
	
	return 0;
}

Skrypt PHP:

<html>
	<head>
		<title>Obliczanie</title>
	</head>
	<body>
		<h1>Wyniki obliczen</h1>
		<?php
			$starttime = microtime(true);
			for ($i = 0; $i < 100000000; $i++)
			{
				$napis += $i;
			}
			$stoptime = microtime(true);
			
			echo round($stoptime - $starttime, 5);
		?>
	</body>
</html>

Wykonywanie kodu tego typu (tak wielka ilość iteracji) nie zdarza się raczej zbyt często, aczkolwiek daje pewien obraz sytuacji. W pierwszym teście to, który wygra dość łatwo można było przewidzieć. Ale co gdybyśmy chcieli potestować odczyt i zapis do pliku ? Sprawdziłem. Tym razem testowałem trzy rzeczy, pierwsza odczyt plików i zapis w PHP, druga to odczyt i zapis z użyciem strumieni C++, ostatnia rzecz którą testowałem to odczyt oraz zapis pliku z użyciem funkcji API systemu Windows. Wyniki tym razem nie są już aż tak miażdżące, lecz nadal odrazu widać który sposób jest wydajniejszy. W celu lepszego zobrazowania sytuacji stworzyłem wykres. Jest on wyskalowany w sekundach. Rozmiar pliku na którym testowane były operacje zapis / odczyt można w prosty sposób obliczyć: rozmiar_bufora * ilosc_iteracji = ~ 125 MB.

Dołączam równiez kod C++ użyty do odczytu / zapisu Win32 :

#include <iostream>
#include <string>

#include "PerformanceTimer.h"

using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	DWORD dwWrite;
	
	HANDLE hFile = CreateFile("plik.bin",
							  GENERIC_READ | GENERIC_WRITE,
							  0,
							  0,
							  CREATE_ALWAYS,
							  0,
							  0);
	char szBuffer[255];
	memset(&szBuffer, 0, sizeof(szBuffer));
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		WriteFile(hFile, szBuffer, sizeof(szBuffer), &dwWrite, 0);
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double) 10000000) << endl;
	CloseHandle(hFile);
	
	hFile = CreateFile("plik.bin",
					   GENERIC_READ | GENERIC_WRITE,
					   0,
					   0,
					   OPEN_EXISTING,
					   0,
					   0);
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		ReadFile(hFile, szBuffer, sizeof(szBuffer), &dwWrite, 0);
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double) 10000000) << endl;
	CloseHandle(hFile);
	
	cout << "</body></html>";
	return 0;
}

Kod użyty do odczytu / zapisu z użyciem strumieni :

#include <iostream>
#include <fstream>
#include <string>

#include "PerformanceTimer.h"
		
using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	char szBuffer[255];
	ofstream file;
	
	memset(&szBuffer, 0, sizeof(szBuffer));
	file.open("plik.bin");
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		file << szBuffer;
	}
	pt.Stop();
	
	file.close();
	cout << (pt.GetTime() / (double) 10000000) << endl;
	
	ifstream file_2("plik.bin");
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		file_2.read(szBuffer, sizeof(szBuffer));
	}
	pt.Stop();
	
	file_2.close();
	cout << (pt.GetTime() / (double) 10000000) << endl;

	cout << "</body></html>";
	return 0;
}

A to kod dla PHP :

<html>
	<head>
		<title>Obliczanie</title>
	</head>
	<body>
		<h1>Wyniki obliczen</h1>
		<?php
			for ($i = 0; $i < 255; $i++) $buffer .= "6";
			
			$file = fopen("plik.bin", "w");
			flock($plik, LOCK_EX);
			
			$starttime = microtime(true);
			for ($i = 0; $i < 500000; $i++)
			{
				fwrite($file, $buffer);
			}
			$stoptime = microtime(true);
			
			flock($file, LOCK_UN);
			fclose($file);
			echo round($stoptime - $starttime, 5) . "<br/>";
			
			$file = fopen("plik.bin", "r");
			flock($file, LOCK_SH);
			
			$starttime = microtime(true);
			for ($i = 0; $i < 500000; $i++)
			{
				fread($file, 255);
			}
			$stoptime = microtime(true);
			
			echo "<br/>" . round($stoptime - $starttime, 5) . "<br/>";
			flock($file, LOCK_UN);
			fclose($file);
		?>
	</body>
</html>

Na koniec mała konkluzja tego testu. Od początku wierzyłem że lepsze wyniki uzyska program pisany w C++ i tak też się okazało. Lecz żeby było ciekawiej, to dodam, nie zawsze wyniki uzyskiwane były tak dobre. Nie wiem od czego to zależy, w każdy razie program uruchamiany osobno (nie poprzez serwer www na żadanie przeglądarki) uzyskiwał stabilniejsze i krótsze czasy. Czasem nawet o 1/3. A w przypadku zapisu do pliku wyniki okazywały się być nawet gorsze (!). Mimo tego jednak uważam, że używanie programów CGI kompilowanych może znacząco podnieść wydajność treści dynamicznej, aczkolwiek jest bardziej złożone niż zwykły skrypt w PHP. Ten test nie miał za zadanie oczywiście w żaden sposób pokazać wyższości jednego języka nad drugim. Obydwa lubię i tak już zostanie. Potraktujcie ten test raczej jako ciekawostkę, bo raczej chyba nikt nie będzie pisał www z użyciem C++.
Kod klasy PerformanceTimer można pobrać z pod tego adresu : http://sourceforge.net/projects/performancetime/files/PerformanceTimer.cab/download Jest to klasa napisana z użyciem kodu zawartego w książce „Windows via C/C++” i ja ten kod opakowałem w klasę aby było wygodniej.

17 lutego 2010

Czcionki dla programistów

Filed under: Programowanie,Uncategorized — winuser @ 11:11
Tags: , , ,

Niestety należę (a może stety?) do ludzi którzy raczej mają jakieś poczucie estetyki. Tak więc przykładam uwagę do tego w czym piszę (chodzi o wygląd IDE) oraz do tego co jest tematem tego wpisu czyli czcionka. W końcu cały czas ją oglądamy podczas pisania. Nie może nas ani męczyć ani być ochydna. Czcionek dla programistów, zwanych czcionkami monotypicznymi czyli o stałej szerokości znaków istnieje na świecie wiele. Wybierać jest w czym, niestety taki już nasz język Polski piękny że istnieją w nim znaki dodatkowe zwane diaktrycznymi. Większość czcionek jak możecie sie domyśleć nie pochodzi z Polski, więc oczywiście po wpisaniu takiego znaku zamiast np. `ą` pojawia się jakiś potocznie zwany krzaczek. Nie jest to w sumie jakiś duży problem z racji tego że kod przecież nie zawiera tych znaków, ale już np. treści komunikatów dla usera mogą je zawierać. Co prawda Courier New z windows`a posiada je, lecz jest to juz troszkę oklepana czcionka, jednym słowem ma swoje lata a co więcej po pewnym czasie pisania człowiek czuje przesyt programowania co jest oczywiście zjawiskiem niepożądanym.
Miałem juz okazję przetestować parę ładnych czcionek monotypicznych, postanowiłem teraz je tutaj zaprezentować.

Do niektórych czcionek nie będę dodawał screenów, ponieważ na stronach domowych są już gotowe. Screeny robione z wyłączonym anty-aliasingiem.

Pierwsza, Triskweline (brak znaków diaktrycznych). Troszkę mała jak dla mnie (rozmiar 10) ale ostatecznie może być. Zaletą jej może byc to, że na mniejszych monitorach zmieści się więcej znaków na tej samej powierzchni ponieważ czcionka została zaprojektowana tak aby była w miarę przejrzysta oraz zajmowała względnie mało miejsca. Pobrać ją możesz stąd http://www.netalive.org/tinkering/triskweline/

Kolejną która miałem okazję wypróbować jest czcionka znana pod nazwą Anonymous którą można pobrać ze strony http://www.ms-studio.com/FontSales/anonymous.html Czcionka praktycznie nie nadaje się do rozmiarów innych niż 10, jest zdecydowanie większa niz Triskweline. Niezbyt ładnie również wygląda jeśli wyłączysz anty-aliasing w Windows`ie, kontury sa postrzępione. Mimo tego przez jakiś czas ją miałem ustawioną jako główną i sprawowała się całkiem nieźle.

Czcionka która jest następna na liście, jest raczej mało znana (na google trudno jej szukać) _M8BT nie wiem czy to jej oryginalna nazwa czy może jakaś kodowa, nie pamiętam również skąd ją mam. Prezentuje się następująco :

Ludziom lubiącym ekstremalnie małe czcionki napewno przypadnie do gustu. Jako że nie można jej znaleźć w internecie wrzuciłem ją na swój serwer i można ją pobrać stąd http://files0.myftp.org/backup/fonts/_M8BT.FON

Nie mogło też oczywiście zabraknąć chyba raczej popularnej czcionki Dina którą można pobrać stąd http://www.donationcoder.com/Software/Jibz/Dina/ Używałem jej również przez pewien czas i jest (zaraz po Courier) jedną z czcionek której nie zmieniałem przez dłuższy okres.

Kolejna czcionka, dość ciekawa zwana IBM3270, jest odpowiednikiem czcionki używanej w tym własnie mikrokomputerze. Można ją pobrać tutaj http://codedwarf.com/pcsansi.fon A jak wygląda ?

Czcionka znana pod nazwą Raize, również godna polecenia która można znaleźć na stronie http://www.raize.com/devtools/tools/rzfont.asp była kolejną której dość długo używałem i byłem z niej zadowolony. Nie jest ani zbyt mała ani zbyt wielka, a co więcej można sobie wybrać jej rozmiar pomiędzy 10 a 14.

A teraz coś dla już bardziej doświadczonych koderów którzy pamiętają środowisko Borland Turbo C++ 4.5. Do pakietu dołączana była czcionka zwana Borland TE w wersji normalnej i pochylonej. Szczerze mówiąc zapowiadała się dość ciekawie ale zawiodła mnie, kod stał się mniej czytelny. Zdecydowanie wolę już od niej Courier New. Nie mniej jeśli ktoś chce sobie popatrzeć może ją pobrać stąd : http://files0.myftp.org/backup/fonts/borte.fon Na załączonym obrazku specjalnie usunąłem oddzielenie nowymi liniami kod aby pokazać jak całość się zlewa.

Ostatnio mam ustawioną ciekawą czcionkę zwaną Crisp którą można pobrać stąd http://files0.myftp.org/backup/fonts/crisp.ttf A oto jak się prezentuje :

Jest kompromisem pomiędzy ekonomicznym wykorzystaniem miejsca na monitorze a czytelnością kodu, za to ją lubię. Rozmiar jaki można ustawić sięga 30, lecz tylko przy 12 wygląda ładnie, przy innych rozmiarach jest postrzępiona i widać piksele.

Przedostatnią czcionką którą chcę wam dziś zaprezentować jest raczej ciekawostką niż czymś co można używać na codzień. Zwana Quartz (coś w tym jest). Dobra raczej do filmów hakerskich w których włamują się przez notatnik do CIA. Wygląda tak :

A pobrać można ją stąd http://files0.myftp.org/backup/fonts/quartz.ttf

Ostatnia czcionka, zwana Courier ma już swoje lata. Była dość popularna w okresie kiedy panowało IDE Microsoft Visual C++ w wersji 5 oraz 6. Stopniowo zastępowana przez nowocześniejczą Courier New oraz w nowszych systemach czcionką Consolas. Jej zaletą jest to że obsługuje znaki diaktryczne. Czcionka ta nie obsługuje anty-aliasingu, mimo tego prezentuje się całkiem dobrze :


Lecz na dłuższą metę troszkę może męczyć. Pobierać jej nie musisz, bo jeśli posiadasz system Windows (minimum 95 zdaje się) to masz ją już w systemie zainstalowaną ; )

Jeśli macie jakieś ciekawe czcionki, podzielcie się nimi w komentarzach, chętnie przetestuję coś nowego.