Optymalizacja, proste metody….

… na oszczędzenie na czasie. Chyba tak. Albo chyba nie? Ale o co chodzi?

Szybko, dobrze i tanio

Jest taka legenda Miejska, która mówi, że pewna mała firma IT w katalogu reklamowym miała napisane:Szybko, Tanio, Solidnie. Wybierz i zapłać za dwa z tych produktów, a my dajemy gwarancję satysfakcji.
Pewien człowiek, zapytał się dlaczego ma wybrać dwa z tych przymiotników. Odpowiedź była oczywista.
Soft można tworzyć szybko i tanio, ale nie solidnie. Można też szybko i solidnie, ale nie jest to tanie. Można w końcu tanio i solidnie, ale będzie to trwało dość długo.
Idąc w myśl tych zasad można powiedzieć, że istnieją też takie trzy cechy oprogramowania, które pozwalają na opisanie sposobów tworzenia kodu. Moim zdaniem są to:

  • Zużycie pamięci
  • Zużycie procesora
  • Elegancja i bezpieczeństwo kodu

Idąc tym tropem opiszę kilka prostych sztuczek, które pozwalają zoptymalizować kod pod kątem jednej z tych cech.

Nienawidzę pętli for

Pierwsza prosta optymalizacja to optymalizacja pod kątem czasu wykonania i zużycia pamięci. Jeżeli mamy pętlę for:

Listing 1.

package eu.runelord.optymalizacja;

public class PetlaFor {

	/** * @param args */
	public static void main(String[] args) {
		PetlaFor petlaFor = new PetlaFor();
		for (int i = 0; i < petlaFor.size(); i++) {
		}

	}

	int size() {
		System.out.print(".");
		return 100;
	}
}

Pytanie jaki będzie wynik?

  • sto [.]
  • nic
  • program się nie skompiluje

Prawidłowa odpowiedź to a. Za każdym obrotem zostanie wywołana metoda obliczająca wielkość. Nic wielkiego jak metoda tylko zwraca jakąś liczbą, a co gdy wykonuje dodatkowe obliczenia, albo jest obłożona interceptorami? Wtedy nie dość, że tracimy czas na powtarzanie obliczeń to jeszcze dodatkowo możemy zająć dużo pamięci.
Rozwiązaniem jest wprowadzenie dodatkowej zmiennej, która będzie przechowywała wynik obliczeń:

Listing 2. Pętla po małej optymalizacji

package eu.runelord.optymalizacja;

public class PetlaFor {

	/** * @param args */
	public static void main(String[] args) {
		PetlaFor petlaFor = new PetlaFor();
		int l = petlaFor.size();
		for (int i = 0; i < l; i++) {
		}

	}

	int size() {
		System.out.print(".");
		return 100;
	}
}

Jest szybko i z małym zużyciem pamięci, ale kod nie jest bezpieczny wielowątkowo. Dlaczego? A no dlatego, że może się okazać, że inny wątek znacznie zmniejszył rozmiary naszego zbioru i wielkość, którą operujemy jest nieprawidłowa. Jak widać nie można być pięknym, mądrym i bogatym.

4 Responses to “Optymalizacja, proste metody….”

  1. Lukasz Says:

    Z tym bezpiecznie wątkowo nie zrozumiałem (brak kawy?), możesz to rozwinąć?

  2. koziołek Says:

    Sprawa stosunkowo prosta. Załóżmy, że masz metodę size(), która zwraca jako wynik ilość elementów w pewnej kolekcji. Kolekcja trafia do wątku z pętlą oraz do innego wątku. Wątek z pętlą pobiera wielkość kolekcji i zaczyna iterację. Po pewnym czasie zostaje przełączony wątek i drugi wątek, który posiada referencję do tej kolekcji usuwa lub dodaje element. Następnie znowu przełączony jest wątek i nasz oryginalny wątek z pętlą ma już błędne dane.

  3. Lukasz Says:

    Tak mi się właśnie zdawało, że twój wpis o thread-safe jest bardziej abstrakcyjny, niż podany przykład.
    Doszedłem do tego trochę później, przy filiżance kawy ;-)

  4. koziołek Says:

    Ja wieczorkiem wrócę z imprezy to dodam kod programu, który ilustruje takie coś. Mam już gotowy, ale nie mam czasu go zamieścić.

Leave a Reply