Jaka jest najbardziej absurdalna pesymizacja, jaką widziałeś? [Zamknięte]


145

Wszyscy wiemy, że przedwczesna optymalizacja jest źródłem wszelkiego zła, ponieważ prowadzi do nieczytelnego / niemożliwego do utrzymania kodu. Jeszcze gorsza jest pesymizacja, kiedy ktoś wdraża „optymalizację”, ponieważ uważa, że będzie szybsza, ale w końcu będzie wolniejsza, jak również buggy, nie w utrzymaniu itp. Jaki jest najbardziej śmieszny przykład tego, jaki widzieliście ?


21
„Pesymizacja” to świetne słowo.
mqp

Na wypadek, gdybyś nie wiedział, rozmawiali o twoim wątku tutaj w najnowszym podcastu.
mmcdole

Odpowiedzi:


81

W starym projekcie odziedziczyliśmy kilku (skądinąd znakomitych) programistów systemów wbudowanych, którzy mieli ogromne doświadczenie z Z-8000.

Naszym nowym środowiskiem był 32-bitowy Sparc Solaris.

Jeden z facetów poszedł i zmienił wszystkie int na krótkie, aby przyspieszyć nasz kod, ponieważ pobranie 16 bitów z pamięci RAM było szybsze niż pobranie 32 bitów.

Musiałem napisać program demonstracyjny, aby pokazać, że pobieranie wartości 32-bitowych w systemie 32-bitowym jest szybsze niż pobieranie wartości 16-bitowych, i wyjaśnić, że aby pobrać wartość 16-bitową, procesor musiał zrobić 32-bitową szerokość dostęp do pamięci, a następnie zamaskowanie lub przesunięcie bitów niepotrzebnych dla wartości 16-bitowej.


16
Hej, gdzie nauczyłeś się matematyki? 2 instrukcje z 1 dostępem do pamięci podręcznej / RAM są oczywiście szybsze niż 1 instrukcja z 1 dostępem do pamięci podręcznej / RAM!
Razor Storm

2
@RazorStorm Na późniejszych maszynach, w których przepustowość i pamięć podręczna są cenniejsze, byłoby odwrotnie. Maska bitowa / przesunięcie jest tania, ale chcesz zmieścić jak najwięcej w pamięci podręcznej, a także zminimalizować przepustowość.
Jed

206

Myślę, że określenie „przedwczesna optymalizacja jest źródłem wszelkiego zła” jest często używane. W przypadku wielu projektów wymówką stało się branie pod uwagę wyników aż do późnej fazy projektu.

To zdanie jest często podpórką dla ludzi, aby uniknąć pracy. Widzę, że to wyrażenie jest używane, gdy ludzie powinni naprawdę powiedzieć: „Ojej, naprawdę nie pomyśleliśmy o tym z góry i nie mamy czasu, aby się tym zająć teraz”.

Widziałem znacznie więcej „śmiesznych” przykładów głupich problemów z wydajnością niż przykłady problemów wprowadzonych z powodu „pesymizacji”

  • Odczytywanie tego samego klucza rejestru tysiące (lub dziesiątki tysięcy) razy podczas uruchamiania programu.
  • Ładowanie tej samej biblioteki DLL setki lub tysiące razy
  • Marnowanie megabajtów pamięci przez niepotrzebne zachowywanie pełnych ścieżek do plików
  • Nie organizują struktur danych, więc zajmują znacznie więcej pamięci, niż potrzebują
  • Zmiana rozmiaru wszystkich ciągów przechowujących nazwy plików lub ścieżki na MAX_PATH
  • Bezpłatne odpytywanie rzeczy, które mają zdarzenia, wywołania zwrotne lub inne mechanizmy powiadamiania

Myślę, że lepszym stwierdzeniem jest to: „optymalizacja bez pomiaru i zrozumienia wcale nie jest optymalizacją - to tylko przypadkowa zmiana”.

Praca z dobrą wydajnością jest czasochłonna - często bardziej niż samo opracowanie funkcji lub komponentu.


46
Kluczowym słowem tego cytatu jest „przedwczesne”. Twoje przeformułowanie na „optymalizacja bez mierzenia i zrozumienia” nie wydaje się zmieniać znaczenia ani trochę. Dokładnie to miał na myśli Knuth.
Bill the Lizard

13
@Foredecker: zaraz. Zbyt wiele osób zapomina kontekst, co stawia ten cytat solidnie przeciwko mikro -optimization. Przeanalizowanie problemu w celu wybrania odpowiedniego algorytmu przed jego wdrożeniem nie jest przedwczesne, ale zbyt często ten cytat jest wyrzucany, aby uzasadnić najbardziej leniwe i najmniej wydajne rozwiązanie.
Shog9,

5
To naprawdę zależy od indywidualnego przypadku, jest więcej przypadków, w których przedwczesna optymalizacja staje się problemem, niż nieodpowiednie planowanie optymalizacji staje się problemem
Mark Rogers

12
-1: Istnieje różnica między „optymalizacją” a odpowiednim projektem. Dla tych, którzy nie wiedzą, dobrą zasadą jest to, że „optymalizacja” sprawia, że ​​kod jest trudniejszy do odczytania, ale szybszy lub bardziej wydajny. Lepszy projekt sprawi, że kod będzie łatwiejszy do odczytania (lub przynajmniej nie gorszy) i bardziej wydajny.
TED

5
Jeśli jest nadużywany, populacja zadająca pytania na temat SO jest silnie obciążona wartościami odstającymi. : D
dkretz

114

Bazy danych to playlista pesymizacji.

Ulubione obejmują:

  • Podziel tabelę na wielokrotności (według zakresu dat, zakresu alfabetycznego itp.), Ponieważ jest „za duża”.
  • Utwórz tabelę archiwum dla wycofanych rekordów, ale kontynuuj UNION z tabelą produkcyjną.
  • Powiel całe bazy danych według (dział / klient / produkt / itp.)
  • Nie dodawaj kolumn do indeksu, ponieważ jest on zbyt duży.
  • Twórz wiele tabel podsumowań, ponieważ ponowne obliczanie z surowych danych jest zbyt wolne.
  • Utwórz kolumny z podpolami, aby zaoszczędzić miejsce.
  • Denormalizuj do pól jako tablicy.

To jest poza moją głową.


Oparcie się potrzebie indeksowania jest po prostu bolesne.
Bill the Lizard

2
Tak, znam kogoś, kto pracuje dla dużej amerykańskiej firmy naftowej, gdzie prawie wszystkie ich tabele mają powiązaną tabelę archiwum, a większość zapytań wybiera z widoków UNION pary tabel. Wydajność jest taka, jakiej można się spodziewać!
Tony Andrews

Hah, myślę, że każdy DBA musiał w pewnym momencie porzucić związek z trasą tablic archiwalnych. Wtedy zawsze wydawało się to rozsądne.
Cruachan

3
Dodam: podzielę bazę na kilka różnych baz (klienci ac, klienci df itp.)
Gabriele D'Antona

Czy mógłbyś rozwinąć temat „Denormalizuj na pola jako tablicę”? Co masz na myśli?
Bart van Heukelom

87

Myślę, że nie ma absolutnej reguły: niektóre rzeczy najlepiej zoptymalizować z góry, a inne nie.

Na przykład pracowałem w firmie, w której otrzymywaliśmy pakiety danych z satelitów. Każdy pakiet kosztuje dużo pieniędzy, więc wszystkie dane były wysoce zoptymalizowane (tj. Spakowane). Na przykład szerokość / długość geograficzna nie została wysłana jako wartości bezwzględne (zmiennoprzecinkowe), ale jako przesunięcia względem „północno-zachodniego” narożnika „bieżącej” strefy. Musieliśmy rozpakować wszystkie dane, zanim mogły zostać użyte. Ale myślę, że to nie jest pesymizacja, to inteligentna optymalizacja w celu zmniejszenia kosztów komunikacji.

Z drugiej strony nasi architekci oprogramowania zdecydowali, że rozpakowane dane powinny zostać sformatowane w bardzo czytelny dokument XML i zapisane w naszej bazie danych jako takie (w przeciwieństwie do przechowywania każdego pola w odpowiedniej kolumnie). Ich pomysł był taki, że „XML to przyszłość”, „miejsce na dysku jest tanie” i „procesor jest tani”, więc nie było potrzeby niczego optymalizować. W rezultacie nasze 16-bajtowe pakiety zostały zamienione na 2kB dokumenty przechowywane w jednej kolumnie, a nawet dla prostych zapytań musieliśmy załadować megabajty dokumentów XML do pamięci! Otrzymywaliśmy ponad 50 pakietów na sekundę, więc możesz sobie wyobrazić, jak potworna stała się wydajność (przy okazji, firma zbankrutowała).

Więc znowu, nie ma absolutnej reguły. Tak, czasami optymalizacja zbyt wczesna jest błędem. Ale czasami motto „procesor / przestrzeń dyskowa / pamięć jest tania” jest prawdziwym źródłem wszelkiego zła.


37
Zgadzam się, że "procesor / przestrzeń dyskowa / pamięć jest tania" to prawdziwy korzeń wszelkiego zła. +1
ksuralta

5
Słyszałem też, że bzdury XML. Kolejna zatankowana firma.
n8wrl

19
@ksuralta: „Procesor / miejsce na dysku / pamięć jest tania” to wygodna wymówka, aby uniknąć myśli. Unikanie myśli jest wyimaginowanym źródłem wszelkiego zła.
Piskvor opuścił budynek

Ta XMLizacja miała miejsce również w moim miejscu pracy, po której nastąpiła JSONizacja. Wszystko po to, aby uniknąć „pracochłonnego” projektowania relacyjnej bazy danych.
Tanz87

75

O dobry Boże, myślę, że widziałem je wszystkie. Najczęściej jest to próba naprawienia problemów z wydajnością przez kogoś, kto jest cholernie leniwy, aby znaleźć przyczynę tych problemów z wydajnością, a nawet zbadanie, czy rzeczywiście występuje problem z wydajnością. W wielu z tych przypadków zastanawiam się, czy nie jest to tylko przypadek osoby, która chce wypróbować konkretną technologię i rozpaczliwie szuka gwoździa pasującego do jej błyszczącego nowego młotka.

Oto ostatni przykład:

Architekt danych przychodzi do mnie z wyszukaną propozycją pionowego podziału tabeli kluczy w dość dużej i złożonej aplikacji. Chce wiedzieć, jakiego rodzaju wysiłki rozwojowe byłyby konieczne, aby dostosować się do zmiany. Rozmowa przebiegała tak:

Ja: Dlaczego to rozważasz? Jaki problem próbujesz rozwiązać?

On: Tabela X jest zbyt szeroka, dzielimy ją na partycje ze względu na wydajność.

Ja: Dlaczego myślisz, że jest za szeroka?

On: Konsultant powiedział, że to o wiele za dużo kolumn w jednej tabeli.

Ja: A to wpływa na wydajność?

On: Tak, użytkownicy zgłaszali sporadyczne spowolnienia w module XYZ aplikacji.

Ja: Skąd wiesz, że szerokość stołu jest źródłem problemu?

On: To jest tabela kluczy używana przez moduł XYZ i ma około 200 kolumn. To musi być problem.

Ja (wyjaśnienie): Ale moduł XYZ w szczególności wykorzystuje większość kolumn w tej tabeli, a kolumny, których używa, są nieprzewidywalne, ponieważ użytkownik konfiguruje aplikację tak, aby wyświetlała dane, które chcą wyświetlić z tej tabeli. Jest prawdopodobne, że w 95% przypadków i tak połączylibyśmy wszystkie stoły razem, co zaszkodziłoby wydajności.

On: Konsultant powiedział, że jest za szeroki i musimy to zmienić.

Ja: Kim jest ten konsultant? Nie wiedziałem, że zatrudniliśmy konsultanta, ani w ogóle nie rozmawiali z zespołem programistów.

On: Cóż, jeszcze ich nie zatrudniliśmy. Jest to część propozycji, którą zaoferowali, ale nalegali, abyśmy ponownie zaprojektowali tę bazę danych.

Ja: Uh huh. Dlatego konsultant, który sprzedaje usługi ponownego projektowania baz danych, uważa, że ​​potrzebujemy przeprojektowania bazy danych ....

Rozmowa trwała i trwała w ten sposób. Następnie ponownie przyjrzałem się tej tabeli i stwierdziłem, że prawdopodobnie można by ją zawęzić za pomocą prostej normalizacji bez potrzeby stosowania egzotycznych strategii partycjonowania. Okazało się to oczywiście kwestią sporną, gdy zbadałem problemy z wydajnością (wcześniej niezgłoszone) i wyśledziłem je według dwóch czynników:

  1. Brak indeksów w kilku kluczowych kolumnach.
  2. Kilku nieuczciwych analityków danych, którzy okresowo blokowali tabele kluczy (w tym te „zbyt szerokie”), wysyłając zapytania do produkcyjnej bazy danych bezpośrednio za pomocą programu MSAccess.

Oczywiście architekt nadal naciska na pionowe podzielenie stołu zawieszonego na „zbyt szerokim” metaproblem. Potwierdził nawet swoją argumentację, otrzymując propozycję od innego konsultanta ds. Baz danych, który był w stanie określić, że potrzebujemy poważnych zmian projektowych w bazie danych bez patrzenia na aplikację lub przeprowadzania jakiejkolwiek analizy wydajności.


Aaag MSAccess to prod. Napisaliśmy procedurę przerywania wszystkich połączeń dostępowych co kilka minut, aż w końcu otrzymaliśmy wiadomość, że jest źle.
Nat

1
Mieliśmy podobną pracę, ale wyszła z użycia. Szczerze mówiąc, Access nie stanowi problemu, po prostu ułatwia neofitom tworzenie / uruchamianie niewykonalnych zapytań.
JohnFx

W naszej firmie jesteśmy zależni od starszych połączeń dostępu ad hoc do produkcyjnej bazy danych. Nie ma to jak kilku zwykłych użytkowników SQL, którzy zapomną o klauzuli WHERE i zablokują główne tabele!
HardCode

35
"Słyszałem, że ma najwięcej pamięci RAM"
Piskvor opuścił budynek

Mogło być gorzej. Edytor zapytań programu Excel blokuje pełną bazę danych podczas jej używania. Kiedy nie wiedziałem o tym, zostawiłem jedno jego wystąpienie otwarte na większą część dnia, podczas gdy pracowałem nad czymś innym. Najgorsze jest to, że MS SQL Server nie zgłosił poprawnej nazwy użytkownika / maszyny, która wykonywała blokadę. Kilka godzin później zdałem sobie sprawę, że to ja byłem przyczyną blokowania, ponieważ tabele były zablokowane jako część widoku, o który pytałem i najpierw sprawdziłem wszystko inne.
Esteban Küber,

58

Widziałem ludzi używających alphadrive-7 do całkowitej inkubacji CHX-LT. To rzadka praktyka. Bardziej powszechną praktyką jest inicjowanie transformatora ZT w celu zmniejszenia buforowania (ze względu na większą odporność na przeciążenie sieci) i tworzenie bajtegraphication w stylu Java.

Całkowicie pesymistyczny!


10
może próbowali
oszukać

6
Zatem w zasadzie jedyną nową zasadą jest to, że zamiast energii generowanej przez względny ruch przewodników i strumieni, jest ona wytwarzana przez modalne oddziaływanie reluktancji magneto i pojemnościowej trwałości?
Matt Rogish,

17
+1, ponieważ mój monitor i tak wymagał czyszczenia ;-)
RBerteig

1
Cholera!! Ale co z efektem ekletromagentyczno-krzyżowo-genetycznym. Myślę, że również należy to wziąć pod uwagę. Lub podmiot może zmienić się w zombie.
Suraj Chandran

1
Trzy słowa: „Chrome Muffler Bearings”.
Allbite

53

Przyznaję, że nic nie wstrząsałoby Ziemią, ale przyłapałem ludzi na używaniu StringBuffer do łączenia ciągów znaków poza pętlą w Javie. To było coś prostego, jak skręcanie

String msg = "Count = " + count + " of " + total + ".";

w

StringBuffer sb = new StringBuffer("Count = ");
sb.append(count);
sb.append(" of ");
sb.append(total);
sb.append(".");
String msg = sb.toString();

Kiedyś dość powszechną praktyką było stosowanie tej techniki w pętli, ponieważ była ona mierzalnie szybsza. Chodzi o to, że StringBuffer jest zsynchronizowany, więc w rzeczywistości istnieje dodatkowe obciążenie, jeśli łączysz tylko kilka ciągów znaków. (Nie wspominając o tym, że różnica jest absolutnie trywialna w tej skali.) Dwie inne kwestie dotyczące tej praktyki:

  1. StringBuilder nie jest zsynchronizowany, dlatego powinien być preferowany w przypadku StringBuffer w przypadkach, gdy kodu nie można wywołać z wielu wątków.
  2. Nowoczesne kompilatory Java zmienią czytelną konkatenację ciągów w zoptymalizowany kod bajtowy dla Ciebie, gdy i tak będzie to odpowiednie.

3
Po pierwsze: dlaczego nie miałbyś używać przynajmniej Java 5? Po drugie: tak, możesz. Jak to się dzieje, że w pierwszym przykładzie możesz policzyć do 5, ale nie w drugim? Używa tych samych literałów String, co pierwszy. Napisz czytelny kod i pozwól kompilatorowi zdecydować, kiedy użyć StringBuffer w tle.
Bill the Lizard

4
@ MetroidFan2002: Literały String w drugim przykładzie są również obiektami. Jak powiedziałem w odpowiedzi, różnice w tej skali są trywialne.
Bill the Lizard

1
Nie oznacza to, że zastępuje każdy ciąg swoim własnym StringBuffer. Optymalizacja, którą wykonuje kompilator, zmniejsza liczbę tworzonych obiektów.
Bill the Lizard

3
@Eric: String msg = "Count =" + count + "of" + total + "."; jest często kompilowany w Javie jako String msg = new StringBuffer (). append ("Count"). append (count) .append ("of") .append (total) .append ("."). toString (); ... co jest dokładnie tym, co robi drugi przykład.
Grant Wagner

3
Panie Wagner, chodzi o to, że TY musisz patrzeć na wszystkie wywołania metod, a nie na kompilator. Musisz je napisać i zrozumieć później. Kompilator i tak robi to samo. Czytelność jest więc w tym przypadku ważniejsza.
ypnos

47

Kiedyś zobaczyłem bazę danych MSSQL, która korzystała z tabeli „Root”. Tabela Root miała cztery kolumny: GUID (uniqueidentifier), ID (int), LastModDate (datetime) i CreateDate (datetime). Wszystkie tabele w bazie danych były kluczami obcymi do tabeli głównej. Ilekroć nowy wiersz został utworzony w dowolnej tabeli w bazie danych, trzeba było użyć kilku procedur składowanych, aby wstawić wpis do tabeli głównej, zanim można było przejść do rzeczywistej tabeli, na której nam zależało (zamiast bazy danych wykonującej zadanie z kilkoma prostymi wyzwalaczami).

To stworzyło bałagan bezużytecznych podsłuchów i bólów głowy, wymagało wszystkiego napisanego na wierzchu, aby użyć sprocesów (i wyeliminowało moje nadzieje na wprowadzenie LINQ do firmy. Było to możliwe, ale po prostu nie warte bólu głowy), a na dodatek nie. nawet nie osiągnąć tego, co do niego należało.

Deweloper, który wybrał tę ścieżkę, bronił jej, zakładając, że zaoszczędziło to mnóstwo miejsca, ponieważ nie używaliśmy Guidów na samych tabelach (ale ... czy GUID nie jest generowany w tabeli głównej dla każdego tworzonego przez nas wiersza?) , w jakiś sposób poprawiło wydajność i ułatwiło audyt zmian w bazie danych.

Aha, i diagram bazy danych wyglądał jak zmutowany pająk z piekła rodem.


42

A co z POBI - pesymizacją oczywiście przez zamiar?

Mój kolega w latach 90. był zmęczony kopaniem w dupę przez dyrektora generalnego tylko dlatego, że pierwszy dzień wydania każdego oprogramowania ERP (niestandardowego) spędził na lokalizowaniu problemów z wydajnością w nowych funkcjach. Nawet jeśli nowe funkcje zajmowały gigabajty i sprawiały, że niemożliwe stało się możliwe, zawsze znajdował jakiś szczegół, a nawet pozornie poważny problem, na który mógł narzekać. Wierzył, że dużo wie o programowaniu i dał się we znaki skopiąc tyłki programistom.

Ze względu na niekompetentny charakter krytyki (był dyrektorem generalnym, a nie informatykiem), mojemu koledze nigdy nie udało się zrobić tego dobrze. Jeśli nie masz problemu z wydajnością, nie możesz go wyeliminować ...

Aż do jednego wydania, umieścił wiele wywołań funkcji Delay (200) (było to Delphi) w nowym kodzie. Zajęło to zaledwie 20 minut po uruchomieniu i kazano mu stawić się w biurze dyrektora generalnego, aby osobiście odebrać zaległe obelgi.

Jedyną niezwykłą rzeczą do tej pory było to, że moi koledzy milczeli, kiedy wracał, uśmiechał się, żartował, wychodził na BigMaca lub dwa, podczas gdy normalnie kopał w stoły, rozpalał się na temat dyrektora generalnego i firmy, a resztę dnia spędził odrzucając na śmierć. .

Oczywiście mój kolega odpoczywał teraz przez jeden lub dwa dni przy biurku, doskonaląc swoje umiejętności celowania w Quake - następnie drugiego lub trzeciego dnia usunął wezwania do opóźnienia, odbudował i udostępnił „awaryjną łatkę”, o której rozpowszechnił informację że spędził 2 dni i 1 noc, aby naprawić dziury w wydajności.

To był pierwszy (i jedyny) raz, kiedy zły prezes powiedział „świetna robota!” do niego. Tylko to się liczy, prawda?

To było prawdziwe POBI.

Ale jest to również rodzaj optymalizacji procesów społecznych, więc jest w 100% w porządku.

Myślę.


10
Pamiętam, jak ktoś pisał o aplikacji do przetwarzania danych, która była sprzedawana na różnych poziomach, gdzie „Lite” mogło pobierać tylko kilka zestawów danych na sekundę, wersja „superduper” tysiące. Jedyną różnicą w kodzie źródłowym jest Sleep (N).
peterchen

1
Znakomity! Poleciłbym ten standard w takiej sytuacji. Na początku programowania przydziel dużą część pamięci i dodaj kilka wezwań usypiających, a gdy potrzebujesz trochę wydajności, po prostu je zmniejsz. Nazywa się to cudotwórcą;)
RCIX

Niestety, łatanie Sleeps do NOPs jest łatwe, więc wersję Lite można bardzo łatwo złamać. Ta rezerwa „optymalizacyjna” może wymagać wykonywalnego programu pakującego, aby utrudnić debugowanie i łatanie.
TheBlastOne

32

„Niezależność bazy danych”. Oznaczało to brak przechowywanych procesów, wyzwalaczy itp. - nawet żadnych kluczy obcych.


8
Czy jest to „niezależność” w tym sensie, że jesteś tak daleko ponad bazą danych, że zapomniałeś, czym są dane? Niepotrzebne abstrahowanie od baz danych „w celu uniknięcia problemów związanych z migracją” jest irytacją; nie będziesz tego potrzebować.
Rob

8
Dość dużo. Astronauci architektury przy pracy. Tworzę aplikacje internetowe, odkąd pojawił się Internet i przez cały ten czas nigdy nie przeniosłem się z jednej platformy bazy danych na drugą.
Chris

5
Jestem pewien, że tak się dzieje, ale rzadko jesteś idiotą, jeśli projektujesz architekturę wokół takiej możliwości.
Chris

6
harpo, to inna sytuacja - w tym przypadku jest to wymóg. Mówię o tym, kiedy nie jest to wymagane, ale AA decyduje, że w pewnym momencie może tak być.
Chris

3
@Wszystko: niezależność od bazy danych może Cię kosztować, tak, ale nasz produkt działa w środowiskach, w których dostawca DB jest wybierany na podstawie ofert, a my w zasadzie musimy grać. Niektórzy programiści nie mają luksusu zintegrowanego pionowo stosu oprogramowania i mimo to muszą sobie radzić.
Chris R

31
var stringBuilder = new StringBuilder();
stringBuilder.Append(myObj.a + myObj.b + myObj.c + myObj.d);
string cat = stringBuilder.ToString();

Najlepsze zastosowanie StringBuildera, jakie kiedykolwiek widziałem.


9
Mów o „niejasnej koncepcji”! Łał!
Eddie,

3
Chłodny. „Mój kierownik mówi, że muszę użyć klasy StringBuilder, jeśli chcę łączyć ciągi. To właśnie robię. Więc co się stało?” Lol ...
TheBlastOne

26

Używanie wyrażenia regularnego do dzielenia łańcucha, gdy wystarczy prosty ciąg


25
ALE w Javie String.Split używa wyrażenia regularnego!
Frank Krueger

Nie rozumiem, jak Regex mógłby być tak szybki, jak wewnętrzny podział ciągu.
Andrei Rînea

2
Ale celowe wyszukanie wyrażenia regularnego używanego do dzielenia łańcuchów i zastąpienie go „prostą” funkcją podziału brzmi jak doskonały przykład pesymizacji. Biblioteki Regex są wystarczająco szybkie.
David Crawshaw

5
@David Crawshaw: Polowanie na możliwości mikro-optymalizacji marnuje czas ludzki; bud pisząc kod, używaj najmniej złożonego wystarczającego rozwiązania.
Piskvor opuścił budynek

6
-1: Jeśli jesteś przyzwyczajony do wyrażeń regularnych, pisanie tego jest bardzo naturalne, zamiast przyzwyczaić się do 1001 wewnętrznych manipulatorów napisów w języku.
KillianDS

26

Bardzo późno do tego wątku wiem, ale widziałem to ostatnio:

bool isFinished = GetIsFinished();

switch (isFinished)
{
    case true:
        DoFinish();
        break;

    case false:
        DoNextStep();
        break;

    default:
        DoNextStep();
}

Wiesz, na wypadek gdyby wartość logiczna miała jakieś dodatkowe wartości ...


22
Prawda, fałsz oczywiście nie znaleziono pliku
Ikke

Hej, zawsze powinieneś mieć domyślny / case else / etc. Co się stanie, gdy jakaś inteligentna osoba zmieni tę wartość logiczną na wyliczenie, aby odzwierciedlić inny status, a następnie następna osoba doda ją do wyliczenia i zapomni o zmodyfikowaniu procedury? Posiadanie wartości domyślnej, gdy nie potrzebujesz, nie kosztuje czasu wykonania i bardzo mało czasu na rozwój. Wyśledzenie przypadkowo wprowadzonego błędu logicznego, który pojawia się podczas działania ... To kosztuje czas, pieniądze i reputację. Ścieg w czasie oszczędza dziewięć.
Oorang

1
@Oorang ... dlaczego w ogóle miałbyś to mieć jako przełącznik? Jest to wartość logiczna - wystarczy jeśli / else.
Damovisa

@Damovisa facepalm dobrze ... więc dobrze :) Przegapiłem to :)
Przegapiłem

2
To było Nullable <Boolean> ... :)
George Chakhidze

25

Najgorszym przykładem, jaki przychodzi mi do głowy, jest wewnętrzna baza danych w mojej firmie, zawierająca informacje o wszystkich pracownikach. Otrzymuje co noc aktualizację od HR i ma na wierzchu usługę sieciową ASP.NET. Wiele innych aplikacji używa usługi internetowej do wypełniania takich elementów, jak pola wyszukiwania / rozwijane.

Pesymizm polega na tym, że deweloper pomyślał, że powtarzające się wywołania usługi internetowej byłyby zbyt wolne, aby wykonywać powtarzające się zapytania SQL. Więc co on zrobił? Zdarzenie uruchamiania aplikacji odczytuje całą bazę danych i konwertuje to wszystko na obiekty w pamięci, przechowywane przez czas nieokreślony, aż pula aplikacji zostanie odtworzona. Ten kod był tak wolny, że załadowanie go zajęłoby 15 minut przy mniej niż 2000 pracownikach. Jeśli nieumyślnie odtworzyłeś pulę aplikacji w ciągu dnia, może to zająć 30 minut lub dłużej, ponieważ każde żądanie usługi sieci Web uruchomiłoby wiele równoczesnych ponownych ładowań. Z tego powodu nowi pracownicy nie pojawiliby się w bazie danych pierwszego dnia, w którym utworzono ich konto, i dlatego nie mogliby uzyskać dostępu do większości wewnętrznych aplikacji przez pierwsze kilka dni, kręcąc kciukami.

Drugi poziom pesymizmu polega na tym, że menedżer ds. Rozwoju nie chce go dotykać z obawy przed złamaniem zależnych aplikacji, ale nadal mamy sporadyczne przerwy w działaniu krytycznych aplikacji w całej firmie z powodu złego projektu tak prostego komponentu.


28
Zarządzanie w najlepszym wydaniu - „Nie, nie poświęcajmy jednorazowo 80 godzin programistom na naprawę tej aplikacji, to jest zbyt drogie. Po prostu zachowajmy ją, aby jej błędy pochłaniały ponad 200 godzin użytkowników miesięcznie plus 10 godzin programisty miesięcznie 'konserwacja'." AAAAAAAAUGH !!!
Piskvor opuścił budynek

25

Wygląda na to, że nikt nie wspomniał o sortowaniu, więc to zrobię.

Kilka różnych razy odkryłem, że ktoś ręcznie stworzył bubbleort, ponieważ sytuacja „nie wymagała” wywołania „zbyt wyszukanego” algorytmu szybkiego sortowania, który już istniał. Deweloper był usatysfakcjonowany, gdy ich ręcznie wykonany bąbelkowy port działał wystarczająco dobrze na dziesięciu wierszach danych, których używają do testów. Nie poszło tak dobrze po dodaniu przez klienta kilku tysięcy wierszy.


2
Zrobiłem to sam raz, kiedy ustaliłem, że zazwyczaj n = 2. Późniejsze ulepszenia produktu unieważniły moje założenie, a kod został zastąpiony PDQ.
Mark Ransom

2
Tak, ale fajnie jest napisać coś opartego na algorytmie co jakiś czas;)
UpTheCreek

20

Kiedyś pracowałem nad aplikacją, która była pełna takiego kodu:

 1 tuple *FindTuple( DataSet *set, int target ) {
 2     tuple *found = null;
 3     tuple *curr = GetFirstTupleOfSet(set);
 4     while (curr) {
 5         if (curr->id == target)
 6             found = curr;
 7         curr = GetNextTuple(curr);
 8     }
 9     return found;
10 }

Wystarczy usunąć found, wrócić nullna koniec i zmienić szóstą linię na:

            return curr;

Podwojono wydajność aplikacji.


1
Pracowałem kiedyś w firmie, w której wytyczne dotyczące kodowania wymagały „tylko jednego zwrotu na koniec” (w celu utrzymania). I rzeczywiście, niektórzy wypluwają kod podobny do twojego, ponieważ nie myślą (oczywistym rozwiązaniem było w większości przypadków użycie goto do wyjścia proc lub zmiana warunków wyjścia pętli)
flolo

12
Zwrotny kurs powoduje w tym przypadku wyraźnie inne zachowanie. Kiedy zwracasz curr, otrzymujesz PIERWSZE dopasowanie, gdzie kod, który wkleiłeś, zwraca OSTATNIE dopasowanie.
SoapBox

2
@SoapBox: Masz rację. @Dour High Arch: Wzrost wydajności nie miał nic wspólnego z regułą pojedynczego powrotu, ponieważ flolo powiedział, że zmiana warunku pętli na (znaleziono aktualny &&!) Miałoby ten sam efekt. GOTO do wyjścia z proc jest okropne i przeczy celowi wytycznej pojedynczego powrotu.
Akusete

2
Dobre komentarze wszystkim. W tym przypadku powinna istnieć tylko jedna krotka z każdym identyfikatorem.
Dour High Arch

7
Nie jest to jednak „pesymizacja”, prawda? To po prostu optymalizacja, która czeka na wykonanie.
Tim Long

20

Kiedyś musiałem spróbować zmodyfikować kod, który zawierał te klejnoty w klasie Constants

public static String COMMA_DELIMINATOR=",";
public static String COMMA_SPACE_DELIMINATOR=", ";
public static String COLIN_DELIMINATOR=":";

Każdy z nich był używany wielokrotnie w pozostałej części aplikacji do różnych celów. COMMA_DELIMINATOR zaśmiecił kod ponad 200 zastosowaniami w 8 różnych pakietach.


Przynajmniej coś takiego jest łatwe do znalezienia / zastąpienia ze źródła - nadal, moje współczucie.
Erik Forbes,

12
Również - Odrobaczacz? Myślałem, że było to zapisane jako „delimiter”. Deliminator brzmi jak zły film z połowy lat 90., który w jakiś sposób ma 3 sekwencje ...........
Erik Forbes

53
Deliminator III: Rise of the Commas
Rob

33
Z drugiej strony, cieszę się, że widzę właściwe rozgraniczenie Colinsa. Każdy warty swojej soli programista wie, że jeśli jest jedna rzecz, którą bezwzględnie musisz oddzielić od siebie, to jest nią przeklęty Colins.
Rob

2
Nie jest łatwo znaleźć i wymienić. Ponieważ każdy jest używany do różnych celów. Każdy dobry programista zrobiłby przynajmniej coś takiego: COUNTRY_LIST_DELIM = ...
CLASSIFICATION_DELIM

19

Największy numer jeden w historii, z którym wielokrotnie spotykałem się w oprogramowaniu wewnętrznym:

Nie korzystamy z funkcji DBMS z powodów „przenośności”, ponieważ „moglibyśmy chcieć później zmienić dostawcę”.

Przeczytaj moje usta. W przypadku jakichkolwiek prac wewnętrznych: TO NIE SIĘ ZDARZY!


9
To się zdarza. MySQL -> postgresql, więc nic nie straciliśmy .
Thomas,

Lub postgres / postgis -> sqlite / spatialite ... To był wrzód na dupie ...
Philip

zdarza się to w testach JUnit
kachanov

17

Miałem współpracownika, który próbował przechytrzyć optymalizator naszego kompilatora C i rutynę przepisał kod, który tylko on mógł odczytać. Jedną z jego ulubionych sztuczek była zmiana czytelnej metody, takiej jak (tworzenie kodu):

int some_method(int input1, int input2) {
    int x;
    if (input1 == -1) {
        return 0;
    }
    if (input1 == input2) {
        return input1;
    }
    ... a long expression here ...
    return x;
}

zaangażowany w to:

int some_method() {
    return (input == -1) ? 0 : (input1 == input2) ? input 1 :
           ... a long expression ...
           ... a long expression ...
           ... a long expression ...
}

Oznacza to, że pierwsza linia metody, którą można było kiedyś odczytać, returnzmieniłaby się w „ ”, a cała inna logika została zastąpiona głęboko zagnieżdżonymi wyrażeniami terniarnymi. Kiedy próbowałeś spierać się o to, dlaczego jest to niemożliwe do utrzymania, wskazywał na fakt, że wynik montażu jego metody był o trzy lub cztery instrukcje montażu krótszy. Niekoniecznie było to szybsze, ale zawsze było małe nieco krótszy. Był to system wbudowany, w którym użycie pamięci czasami miało znaczenie, ale można było dokonać znacznie łatwiejszych optymalizacji niż ta, która pozostawiłaby kod czytelny.

Następnie, z jakiegoś powodu, uznał, że jest ptr->structElementto zbyt nieczytelne, więc zaczął zmieniać to wszystko (*ptr).structElementna teorię, że jest bardziej czytelny i szybszy.

Przekształcanie czytelnego kodu w nieczytelny kod, co najwyżej o 1%, a czasem nawet wolniejszy kod.


Jeśli wspomniany moduł jest nazywany milionami razy na pętlę, to zaakceptowałbym tę optymalizację, o ile tylko skomentuje to, do cholery.
Michael Dorgan,

2
@Michael: Nie zrobiłbym tego, gdyby nie pomiary wskazujące, że był szybszy , a nie tylko krótszy .
dsimcha

W większości sytuacji operator trójskładnikowy jest bardziej czytelny niż if. Nacisk na stwierdzenia zamiast wyrażeń w C jest dogmatem kulturowym / religijnym, a nie jakąkolwiek obiektywną praktyką. (Lepsza wskazówka: jeśli zagnieżdżony trójskładnik jest zbyt długi, aby go przeczytać, nie powinieneś go również używać if.)
Leushenko

2
Chodzi tutaj o pobranie całej funkcji i zastąpienie jej pojedynczą instrukcją, zwrotem, zastępując w ten sposób całą logikę całej funkcji zagnieżdżonymi trójkami. Gdybyś to zobaczył, zrozumiałbyś. To nie jest religijna rzecz „nienawidzę operatorów trójskładnikowych”. Nie mówię o wzięciu pojedynczego ifw funkcji i zastąpieniu go trójskładnikiem. To dobrze i często jest bardziej czytelne. Mówię o zastąpieniu całej metody 30+ linii pojedynczą instrukcją powrotu i zagnieżdżonymi trójkami. Nikt nie sądził, że nowy kod jest bardziej czytelny, ale jeden programista uznał, że jest szybszy.
Eddie

15

Podczas jednej z moich pierwszych prac jako pełnoprawny programista przejąłem projekt programu, który miał problemy ze skalowaniem. Działałby dość dobrze na małych zestawach danych, ale całkowicie się zawiesiłby przy dużych ilościach danych.

Kiedy zacząłem kopać, odkryłem, że pierwotny programista chciał przyspieszyć działanie poprzez zrównoleglenie analizy - uruchamiając nowy wątek dla każdego dodatkowego źródła danych. Jednak popełnił błąd, polegając na tym, że wszystkie wątki wymagały wspólnego zasobu, na którym były zakleszczone. Oczywiście zniknęły wszystkie zalety współbieżności. Co więcej, powodował awarię większości systemów i uruchamiał ponad 100 wątków tylko po to, aby zablokować wszystkie oprócz jednego. Wyjątkiem była moja potężna maszyna deweloperska, która przeszła przez zbiór danych ze 150 źródeł w około 6 godzin.

Aby to naprawić, usunąłem komponenty wielowątkowe i wyczyściłem I / O. Bez innych zmian czas wykonania na zestawie danych ze 150 źródłami spadł poniżej 10 minut na moim komputerze, az nieskończoności do poniżej pół godziny na przeciętnym komputerze firmowym.


Po prostu zapobiegam temu w dzisiejszym projekcie. Teraz wiem, że dokonałem dobrego wyboru.
deadalnix,

14

Przypuszczam, że mógłbym zaoferować ten klejnot:

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    // Find out how many bytes our value uses
    // so we don't do any uneeded work.
    if (value & 0xffff0000)
    {
        if ((value & 0xff000000) == 0)
            tmp = 3;
        else
            tmp = 4;
    }
    else if (value & 0x0000ff00)
        tmp = 2;

    switch (tmp)
    {
        case 4:
            ISQRT_INNER(15);
            ISQRT_INNER(14);
            ISQRT_INNER(13);
            ISQRT_INNER(12);
        case 3:
            ISQRT_INNER(11);
            ISQRT_INNER(10);
            ISQRT_INNER( 9);
            ISQRT_INNER( 8);
        case 2:
            ISQRT_INNER( 7);
            ISQRT_INNER( 6);
            ISQRT_INNER( 5);
            ISQRT_INNER( 4);
        case 1:
            ISQRT_INNER( 3);
            ISQRT_INNER( 2);
            ISQRT_INNER( 1);
            ISQRT_INNER( 0);
    }
#undef ISQRT_INNER
    return root;
}

Ponieważ pierwiastek kwadratowy został obliczony w bardzo wrażliwym miejscu, otrzymałem zadanie znalezienia sposobu na przyspieszenie. Ta niewielka refaktoryzacja skróciła czas wykonywania o jedną trzecią (dla kombinacji używanego sprzętu i kompilatora, YMMV):

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    ISQRT_INNER (15);
    ISQRT_INNER (14);
    ISQRT_INNER (13);
    ISQRT_INNER (12);
    ISQRT_INNER (11);
    ISQRT_INNER (10);
    ISQRT_INNER ( 9);
    ISQRT_INNER ( 8);
    ISQRT_INNER ( 7);
    ISQRT_INNER ( 6);
    ISQRT_INNER ( 5);
    ISQRT_INNER ( 4);
    ISQRT_INNER ( 3);
    ISQRT_INNER ( 2);
    ISQRT_INNER ( 1);
    ISQRT_INNER ( 0);

#undef ISQRT_INNER
    return root;
}

Oczywiście są na to szybsze ORAZ lepsze sposoby, ale myślę, że jest to całkiem niezły przykład pesymizacji.

Edycja: Pomyśl o tym, rozwinięta pętla była w rzeczywistości również zgrabną pesymizacją. Przeglądając kontrolę wersji mogę również przedstawić drugi etap refaktoryzacji, który wypadł jeszcze lepiej niż powyższe:

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1 << 30, root = 0;

    while (tmp != 0)
    {
        if (value >= root + tmp) {
            value -= root + tmp;
            root += tmp << 1;
        }
        root >>= 1;
        tmp >>= 2;
    }

    return root;
}

To jest dokładnie ten sam algorytm, choć nieco inna implementacja, więc przypuszczam, że się kwalifikuje.


Przypuszczam , że isqrt()oblicza floor(sqrt()), ale dlaczego ten kod działa?
Pablo H,

11

Może to być na wyższym poziomie niż to, czego szukałeś, ale naprawienie tego (jeśli masz pozwolenie) wiąże się również z wyższym poziomem bólu:

Naleganie na ręczne rozwijanie Menedżera relacji z obiektami / warstwy dostępu do danych zamiast korzystania z jednej z uznanych, przetestowanych, dojrzałych bibliotek (nawet po tym, jak zostały ci wskazane).


Nie zawsze jest złym pomysłem zrobienie własnego kodu. Jak powiedział kiedyś mędrzec, znajdź zależności i wyeliminuj je. Jeśli jest to podstawowa funkcja biznesowa, zrób to sam.
Kibbee

Nigdy nie wywnioskowałem, że to zawsze zły pomysł. O ile nie powiesz, że Frans Bouma lub podobny, wątpię, czy rzeczy ORM / DAL są podstawową funkcją biznesową. Pisanie własnego odpowiednika jest niezwykle nieopłacalne, co jest przypadkiem ponownego wynalezienia (kwadratowego) koła, zwykle z powodu zespołu NIH.
Gordon Hartley,

@Kibbee - zgadzam się. Lepiej jest stworzyć własny i zrozumieć go niż korzystać z zależności innych firm. Kiedy się zepsuje (i będzie), przynajmniej możesz to naprawić. Znalazłem w przeszłości błędy w Hibernate i Apache Commons, które całkowicie zabijały wydajność naszej aplikacji.
CodingWithSpike,

4
Ręczne obracanie jest naprawdę jedyną opcją, jeśli żadna z uznanych opcji nie ma krytycznej funkcji, której potrzebujesz.
staticsan

3
Właściwie, biorąc pod uwagę niektóre z powyższych komentarzy, trochę więcej perspektywy: kolejną pesymizacją jest próba zmuszenia ORM do zrobienia absolutnie wszystkiego. Często jest przydatny w ponad 95% przypadków. W przypadku tych ostatnich 5% znacznie łatwiej jest zrezygnować z ręcznie spreparowanego kodu trwałego / bezpośredniego wywołania procedur składowanych itp. W celu uzyskania wydajności, prostoty lub obu.
Gordon Hartley

10

Wszystkie ograniczenia klucza obcego zostały usunięte z bazy danych, ponieważ w przeciwnym razie byłoby tak wiele błędów.


8

To nie do końca pasuje do pytania, ale i tak wspomnę o tym jako przestroga. Pracowałem nad aplikacją rozproszoną, która działała wolno i poleciałem do DC, aby wziąć udział w spotkaniu, którego głównym celem było rozwiązanie problemu. Kierownik projektu rozpoczął nakreślenie re-architektury mającej na celu rozwiązanie problemu opóźnienia. Zgłosiłem się na ochotnika, że ​​w weekend wykonałem pomiary, które pozwoliły na odizolowanie wąskiego gardła od jednej metody. Okazało się, że podczas lokalnego wyszukiwania brakowało rekordu, przez co aplikacja musiała przejść do zdalnego serwera przy każdej transakcji. Dodając rekord z powrotem do lokalnego sklepu, opóźnienie zostało wyeliminowane - problem rozwiązany. Zwróć uwagę, że zmiana architektury nie rozwiązałaby problemu.


8

Sprawdzanie przed KAŻDĄ operacją javascript, czy obiekt na którym operujesz istnieje.

if (myObj) { //or its evil cousin, if (myObj != null) {
    label.text = myObj.value; 
    // we know label exists because it has already been 
    // checked in a big if block somewhere at the top
}

Mój problem z tego typu kodem polega na tym, że nikt nie obchodzi, co jeśli nie istnieje? Po prostu nic nie rób? Nie przekazujesz opinii użytkownikowi?

Zgadzam się, że Object expectedbłędy są irytujące, ale to nie jest na to najlepsze rozwiązanie.


Jakie jest zatem najlepsze rozwiązanie? Uważam, że pisanie kodu, w którym czasami zdarzają się błędy, jest niechlujne, nawet jeśli nie mają one bezpośrednich konsekwencji. Oczywiście nie powinieneś tego robić, jeśli nie spodziewasz się, że obiekt będzie pusty w żadnych okolicznościach - może o to Ci chodziło.
simon

7

Co powiesz na ekstremizm YAGNI. Jest to forma przedwczesnej pesymizacji. Wygląda na to, że za każdym razem, gdy zastosujesz YAGNI, w końcu go potrzebujesz, co powoduje 10 razy większy wysiłek, aby go dodać, niż gdybyś dodawał go na początku. Jeśli stworzysz udany program, prawdopodobnie będziesz go potrzebować. Jeśli jesteś przyzwyczajony do tworzenia programów, których życie szybko się kończy, kontynuuj praktykę YAGNI, ponieważ przypuszczam, że wtedy YAGNI.


3
Dziękuję, mam dość tych kiepskich akronimów „ekstremalnego programowania” i tego, jak ludzie używają ich do wspierania leniwych, przynoszących efekt przeciwny do zamierzonych praktyk.
JAL

Badania rzeczywistych projektów pokazują, że rzeczywisty współczynnik między kodem jednorazowym a ponownym użytkowaniem wynosi średnio około 3. Tak więc 10 to tylko „odczuwalna” wartość, ale masz rację z powodu zamiaru.
peterchen

@peterchen - czy mówisz, że badania pokazują, że napisanie kodu wielokrotnego użytku jako kodu jednorazowego zajmuje trzy razy więcej czasu, czy też pokazują, że konwersja kodu jednorazowego na kod wielokrotnego użytku zajmuje trzy razy więcej czasu niż napisanie kod wielokrotnego użytku w pierwszej kolejności?
Jeff Sternal

@jeff: IIRC porównali pewne miary złożoności (cokolwiek o nich myślisz) wbudowanych fragmentów, które zostały przeniesione do oddzielnych metod. Złożoność wzrasta ze względu na obsługę dodatkowych przypadków, sprawdzanie parametrów itp. (Co pozwala przypuszczać, że metody były raczej małe). Spróbuję znaleźć odniesienie.
peterchen

6

Niezupełnie przedwczesna optymalizacja - ale z pewnością błędna - została przeczytana na stronie internetowej BBC, z artykułu omawiającego Windows 7.

Pan Curran powiedział, że zespół Microsoft Windows zajmował się każdym aspektem systemu operacyjnego, aby wprowadzić ulepszenia. „Udało nam się skrócić czas wyłączania o 400 milisekund dzięki niewielkiemu przycięciu muzyki zamykającej plik WAV.

Nie próbowałem jeszcze systemu Windows 7, więc mogę się mylić, ale jestem gotów założyć się, że są tam inne problemy, które są ważniejsze niż czas potrzebny do zamknięcia. W końcu, kiedy widzę komunikat „Zamykanie systemu Windows”, monitor wyłącza się i odchodzę - jakie korzyści daje mi to 400 milisekund?


Prawdopodobnie przekonasz się, że inne kwestie nie są tak łatwe do wyjaśnienia osobom nie będącym programistami na stronie internetowej BBC.
Tom Leys

To jest kąt, którego nie rozważałem - może zaczynam tracić swój cynizm :-)
belugabob

To 400 ms to 400 ms poboru mocy. Prawdopodobnie nieistotne, ale może z czasem się sumuje. Jednak nie jest to coś, o co bym się martwił.
ZachS

1
Straciłem w sumie wiele godzin, czekając na zamknięcie maszyn wirtualnych XP, aby móc przejść do następnej rzeczy. Jestem bardzo wdzięczny za szybsze zamknięcie.
James

1
Co ciekawe, pliki WAV są odtwarzane asynchronicznie, tak długo, jak fanfara zamykania jest krótsza niż czas potrzebny do wyłączenia, przycinanie pliku WAV nic nie robi. A co ciekawsze, jeśli tak bardzo zoptymalizowali zamykanie, dlaczego każde zamknięcie systemu Windows potrzebuje eonów, zanim naprawdę się wyłączy? (Oczywiście z wyjątkiem użycia dużego czerwonego przycisku.)
TheBlastOne

6

Ktoś z mojego działu napisał kiedyś klasę smyczków. Interfejs podobny doCString , ale bez zależności od systemu Windows.

Jedną z "optymalizacji", którą zrobili, było nie przydzielanie większej ilości pamięci niż to konieczne. Najwyraźniej nie zdajemy sobie sprawy, że powodem, dla którego klasy takie jak std::stringprzydzielają nadmiar pamięci, jest sekwencja+= operacji może być wykonywana w czasie O (n).

Zamiast tego każde pojedyncze +=wywołanie wymuszało realokację, która zmieniała powtarzające się dołączenia w algorytm O (n²) Schlemiela the Paintera .


5

Mój były współpracownik ( właściwie soab ) został wyznaczony do zbudowania nowego modułu dla naszego Java ERP, który powinien był zbierać i analizować dane klientów (branża detaliczna). Zdecydował się podzielić KAŻDE pole kalendarza / daty i godziny na jego składniki (sekundy, minuty, godziny, dzień, miesiąc, rok, dzień tygodnia, dwumetr, trymestr (!)), Ponieważ „jak inaczej miałbym zapytać o„ każdy poniedziałek ”?


3
To nie jest przedwczesna optymalizacja, pomyślał, że musi to zrobić dla poprawności
pirolistyczna

Jasne, pomyślał , że tego potrzebuje, ale ponieważ większość DBMS ma jakąś funkcję DAYOFWEEK (znacznik czasu), zrobienie tego bałaganu z góry jest moim zdaniem wystarczająco przedwczesne :)
Joril

1
Nie użyłbym go do OLTP, ale gdybyś „analizował dane klienta”, byłby to w rzeczywistości bardzo elastyczny sposób projektowania hurtowni danych (o ile data i godzina są podzielone na różne wymiary). Czy naprawdę chciałbyś wywołać DAYOFWEEK () dla milionów wierszy danych, czy po prostu przeszukać indeks w polu całkowitoliczbowym?
Tim Medora,

Cóż, nie wiem, czy było tyle
awantur

3

Bez obrazy dla nikogo, ale właśnie oceniłem zadanie (java), które to miało

import java.lang.*;

1
Jeśli nie jest to klasa na wyższym poziomie, myślę, że musisz trochę zwolnić tę uczennicę, chyba że nauczyłeś ją wystarczająco, aby wiedzieć, dlaczego to nie jest dobry pomysł.
Bryan Oakley,

24
Czy będę jedynym, który zauważy ironię nauczyciela dzwoniącego do WTF na kodzie ucznia, że ​​jest on odpowiedzialny za nauczanie poprawnego programowania?
JohnFx,

3
Tak, nie widzę, żeby to bolało. W najgorszym przypadku jest to niepotrzebne. Uczniowie mają tendencję do uciekania się do sztywnej spójności podczas nauki, a importowanie java.lang jest ściśle zgodne z tym, czego uczeń nauczył się o importowaniu.
cygil

1
Dziękuję wszystkim za powiedzenie mi oczywistości. To było zadanie z biologii obliczeniowej i nie liczyłem go, ani nawet o nim nie wspomniałem.
Przeleciał

2
@JohnFX: Oceniający i nauczyciel nie zawsze są tą samą osobą.
Eddie,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.