Jak działa realizacja różnicowa?

Widziałem kilka wzmianek o tym na Stack Overflow, ale wpatrywanie się w Wikipedię (odpowiednia strona została usunięta) i w MFC dynamic dialog demo nic mnie nie oświeciło. Czy ktoś może to wyjaśnić? Nauka zupełnie innej koncepcji brzmi nieźle.


Bazując na odpowiedziach: myślę, że lepiej mi się z tym kojarzy. Chyba za pierwszym razem nie przyjrzałem się wystarczająco uważnie kodowi źródłowemu. Mam mieszane uczucia co do różnic egzekucja w tym momencie. Z jednej strony może znacznie ułatwić niektóre zadania. Z drugiej strony, uruchomienie go i uruchomienie (to znaczy skonfigurowanie go w wybranym języku) nie jest łatwe(jestem pewien, że byłoby to, gdybym zrozumiał to lepiej)...chociaż myślę, że zestaw narzędzi do tego trzeba zrobić tylko raz, a następnie rozszerzyć w razie potrzeby. Myślę, że aby naprawdę to zrozumieć, prawdopodobnie będę musiał spróbować zaimplementować to w innym języku.

Author: Prof. Falken, 2008-12-16

4 answers

Rany, Brian, szkoda, że nie widziałem twojego pytania wcześniej. Ponieważ jest to prawie mój "wynalazek "(na dobre i na złe), może będę w stanie pomóc.

Wstawiony: możliwie najkrótszy wyjaśnię, że jeśli normalne wykonanie jest jak rzucanie piłka w powietrzu i łapanie jej, a następnie wykonanie różnicowe jest jak żonglerka.

@windfinder 's explanation is different from my, and that' s OK. Technika ta nie jest łatwa do owinięcia głową, a Zajęło mi to jakieś 20 lat (off and on), aby znaleźć wyjaśnienia, które działają. Pozwól, że spróbuję jeszcze raz:

    Co to jest?

Wszyscy rozumiemy prostą ideę komputera przechodzącego przez program, pobierającego warunkowe gałęzie oparte na danych wejściowych i robiącego różne rzeczy. (Załóżmy, że mamy do czynienia tylko z prostym strukturalnym kodem goto-less, return-less.) Kod ten zawiera sekwencje instrukcji, podstawowe uporządkowane warunki, proste pętle i podprogramy telefony. (Na razie zapomnij o funkcjach zwracających wartości.)

Teraz wyobraź sobie dwa komputery wykonujące ten sam kod w kroku blokady ze sobą i zdolne do porównywania notatek. Komputer 1 uruchamia się z danymi wejściowymi A, A Komputer 2 z danymi wejściowymi B. działają one krok po kroku obok siebie. Jeśli dojdzie do instrukcji warunkowej, takiej jak IF (test).... ENDIF, a jeśli mają różnicę zdań na temat tego, czy test jest prawdziwy, to ten, który mówi test, jeśli jest fałszywy, przeskakuje do ENDIF i czeka wokół żeby siostra nadrobiła zaległości. (Dlatego kod jest ustrukturyzowany, więc wiemy, że siostra w końcu dostanie się do ENDIF.)

Ponieważ oba komputery mogą ze sobą rozmawiać, mogą porównywać notatki i szczegółowo wyjaśniać, w jaki sposób oba zestawy danych wejściowych i historii wykonania różnią się od siebie.

Oczywiście, w wykonaniu różnicowym (DE) odbywa się to za pomocą jednego komputera, symulując dwa.

Teraz Załóżmy, że masz tylko jeden zestaw danych wejściowych, ale chcesz zobaczyć, jak to zmienił się z czasu 1 na czas 2. Załóżmy, że program, który wykonujesz, jest serializerem / deserializerem. Podczas wykonywania, zarówno serializujesz (zapisujesz) bieżące dane, jak i deserializujesz (wczytujesz) poprzednie dane(które zostały zapisane podczas ostatniego wykonania). Teraz możesz łatwo zobaczyć, jakie są różnice między tym, co dane były ostatnim razem, a tym razem.

Plik, do którego piszesz, i stary plik, z którego czytasz, razem tworzą kolejkę lub FIFO (first-in-first-out), ale to nie jest zbyt głęboka koncepcja.

    Do czego to służy?

Przyszło mi to do głowy, gdy pracowałem nad projektem graficznym, w którym użytkownik mógł konstruować małe procedury procesora wyświetlacza zwane "symbolami", które można było połączyć w większe procedury, aby malować takie rzeczy, jak schematy rur, zbiorników, zaworów, itp. Chcieliśmy, aby diagramy były "dynamiczne" w tym sensie, że mogą stopniowo aktualizować się bez konieczności przerysuj cały diagram. (Sprzęt był powolny jak na dzisiejsze standardy.) Zdałem sobie sprawę, że (na przykład) procedura rysowania słupka wykresu słupkowego może zapamiętać jego starą wysokość i po prostu stopniowo aktualizować się.

To brzmi jak OOP, prawda? Jednak zamiast "zrobić ""obiekt", mogłem skorzystać z przewidywalności sekwencji wykonawczej procedury diagramu. Mógłbym zapisać wysokość paska w sekwencyjnym strumieniu bajtów. Następnie, aby zaktualizować obraz, mogę po prostu uruchomić procedura w trybie, w którym kolejno odczytuje swoje stare parametry, podczas gdy zapisuje nowe parametry, aby być gotowym do następnej aktualizacji.

Wydaje się to głupio oczywiste i wydaje się pękać, gdy tylko procedura zawiera warunek, ponieważ wtedy nowy strumień i stary strumień będą się zsynchronizować. Ale wtedy dotarło do mnie, że jeśli również serializują wartość logiczną testu warunkowego, mogą wrócić do synchronizacji. Trzeba było trochę czasu, żeby przekonać ja, a następnie, aby udowodnić, że to zawsze zadziała, pod warunkiem, że zastosowana zostanie prosta reguła ("reguła trybu kasowania").

Wynik netto jest taki, że użytkownik może zaprojektować te "dynamiczne Symbole" i złożyć je w większe diagramy, nie martwiąc się o to, jak będą dynamicznie aktualizowane, bez względu na to, jak skomplikowany lub strukturalnie zmienny byłby wyświetlacz.

W tamtych czasach musiałem martwić się o zakłócenia między obiektami wizualnymi, więc wymazywanie jednego nie zaszkodzi innym. Jednak teraz używam tej techniki z kontrolkami Windows i pozwalam Windows zająć się problemami z renderowaniem.

Więc co to osiąga? Oznacza to, że mogę zbudować okno dialogowe, pisząc procedurę malowania elementów sterujących i nie muszę się martwić o zapamiętywanie obiektów sterujących lub radzenie sobie z ich stopniową aktualizacją lub sprawianiem, że pojawiają się/znikają/poruszają się zgodnie z warunkami. Rezultatem jest znacznie mniejszy i prostszy kod źródłowy okna dialogowego, o ok. wielkości, a rzeczy takie jak dynamiczny układ lub zmiana liczby kontrolek lub posiadanie tablic lub siatek kontrolek są trywialne. Ponadto kontrolka taka jak Pole edycji może być trywialnie powiązana z danymi aplikacji, które edytuje, i zawsze będzie udowodniona poprawność i nigdy nie muszę zajmować się jej zdarzeniami. Umieszczenie pola edycji dla zmiennej ciągowej aplikacji jest edycją jednowierszową.
    Dlaczego trudno to zrozumieć?

What I have found hardest to wyjaśnij, że wymaga to odmiennego myślenia o oprogramowaniu. Programiści są tak mocno przywiązani do widoku obiekt-działanie Oprogramowania, że chcą wiedzieć, jakie są obiekty, jakie są klasy, jak "budują" wyświetlacz i jak radzą sobie ze zdarzeniami, że potrzeba bomby wiśniowej, aby wysadzić je z niego. Staram się przekazać, że najważniejsze jest to, co masz do powiedzenia? wyobraź sobie, że budujesz język specyficzny dla domeny (DSL), w którym wszystko, co musisz zrobić, to powiedz mu "Chcę edytować zmienną A tutaj, zmienną B tam i zmienną C tam" i magicznie się tym zajmie. Na przykład w Win32 znajduje się ten "język zasobów" do definiowania okien dialogowych. Jest to doskonale dobry DSL, z tym, że nie idzie wystarczająco daleko. Nie "żyje" w głównym języku proceduralnym, nie obsługuje zdarzeń ani nie zawiera pętli / warunków / podprogramów. Ale to znaczy dobrze, i dynamiczne okna dialogowe próbuje zakończyć zadanie.

Więc inny tryb aby napisać program, najpierw znajdujesz (lub wymyślasz) odpowiedni DSL i kodujesz w nim jak najwięcej swojego programu. Niech to zajmuje się wszystkimi obiektami i działaniami, które istnieją tylko dla implementacji.

Jeśli chcesz naprawdę zrozumieć wykonanie różnicowe i użyć go, istnieje kilka trudnych problemów, które mogą Cię potknąć. Kiedyś zakodowałem go w makrach Lisp , gdzie te trudne bity mogą być obsługiwane za ciebie, ale w " normal" języki wymaga pewnej dyscypliny programisty, aby uniknąć pułapek.

Przepraszam, że tak długo. Jeśli to nie ma sensu, byłbym wdzięczny, gdybyś to wskazał, a ja spróbuję to naprawić.

Dodany:

W Java Swing istnieje przykładowy program o nazwie TextInputDemo. Jest to statyczne okno dialogowe, obejmujące 270 linii (nie licząc listy 50 stanów). W dynamicznych oknach dialogowych (w MFC) jest to około 60 linii:

#define NSTATE (sizeof(states)/sizeof(states[0]))
CString sStreet;
CString sCity;
int iState;
CString sZip;
CString sWholeAddress;

void SetAddress(){
    CString sTemp = states[iState];
    int len = sTemp.GetLength();
    sWholeAddress.Format("%s\r\n%s %s %s", sStreet, sCity, sTemp.Mid(len-3, 2), sZip);
}

void ClearAddress(){
    sWholeAddress = sStreet = sCity = sZip = "";
}

void CDDDemoDlg::deContentsTextInputDemo(){
    int gy0 = P(gy);
    P(www = Width()*2/3);
    deStartHorizontal();
    deStatic(100, 20, "Street Address:");
    deEdit(www - 100, 20, &sStreet);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "City:");
    deEdit(www - 100, 20, &sCity);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "State:");
    deStatic(www - 100 - 20 - 20, 20, states[iState]);
    if (deButton(20, 20, "<")){
        iState = (iState+NSTATE - 1) % NSTATE;
        DD_THROW;
    }
    if (deButton(20, 20, ">")){
        iState = (iState+NSTATE + 1) % NSTATE;
        DD_THROW;
    }
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "Zip:");
    deEdit(www - 100, 20, &sZip);
    deEndHorizontal(20);
    deStartHorizontal();
    P(gx += 100);
    if (deButton((www-100)/2, 20, "Set Address")){
        SetAddress();
        DD_THROW;
    }
    if (deButton((www-100)/2, 20, "Clear Address")){
        ClearAddress();
        DD_THROW;
    }
    deEndHorizontal(20);
    P((gx = www, gy = gy0));
    deStatic(P(Width() - gx), 20*5, (sWholeAddress != "" ? sWholeAddress : "No address set."));
}

Dodany:

Oto przykładowy kod do Edytuj listę pacjentów szpitalnych w około 40 linijkach kodu. Linie 1-6 definiują "bazę danych". Linie 10-23 określają ogólną zawartość interfejsu użytkownika. Linie 30-48 definiują elementy sterujące do edycji rekordu pojedynczego pacjenta. Zauważ, że forma programu prawie nie zwraca uwagi na zdarzenia w czasie, tak jakby wszystko, co musiał zrobić, to utworzyć wyświetlacz raz. Następnie, jeśli obiekty są dodawane lub usuwane lub zachodzą inne zmiany strukturalne, są one po prostu ponownie wykonywane, tak jakby były ponownie tworzone od zera, z wyjątkiem że DE powoduje przyrostową aktualizację zamiast. Zaletą jest to, że programista nie musi poświęcać żadnej uwagi ani pisać kodu, aby przyrostowe aktualizacje interfejsu użytkownika się wydarzyły i są one gwarantowane poprawne. Mogłoby się wydawać, że ponowne wykonanie byłoby problemem z wydajnością, ale tak nie jest, ponieważ aktualizacja kontrolek, które nie wymagają zmiany, trwa dziesiątki nanosekund.

1  class Patient {public:
2    String name;
3    double age;
4    bool smoker; // smoker only relevant if age >= 50
5  };
6  vector< Patient* > patients;

10 void deContents(){ int i;
11   // First, have a label
12   deLabel(200, 20, “Patient name, age, smoker:”);
13   // For each patient, have a row of controls
14   FOR(i=0, i<patients.Count(), i++)
15     deEditOnePatient( P( patients[i] ) );
16   END
17   // Have a button to add a patient
18   if (deButton(50, 20, “Add”)){
19     // When the button is clicked add the patient
20     patients.Add(new Patient);
21     DD_THROW;
22   }
23 }

30 void deEditOnePatient(Patient* p){
31   // Determine field widths
32   int w = (Width()-50)/3;
33   // Controls are laid out horizontally
34   deStartHorizontal();
35     // Have a button to remove this patient
36     if (deButton(50, 20, “Remove”)){
37       patients.Remove(p);
37       DD_THROW;
39     }
40     // Edit fields for name and age
41     deEdit(w, 20, P(&p->name));
42     deEdit(w, 20, P(&p->age));
43     // If age >= 50 have a checkbox for smoker boolean
44     IF(p->age >= 50)
45       deCheckBox(w, 20, “Smoker?”, P(&p->smoker));
46     END
47   deEndHorizontal(20);
48 }

Dodał: Brian zadał dobre pytanie I pomyślałem, że odpowiedź należy do głównego tekstu tutaj:

@Mike: nie jestem pewien, co faktycznie robi "if (deButton(50, 20, "Add")){" statement". Do czego służy funkcja deButton? Czy Twoje pętle FOR / END używają jakiegoś makra? - Brian.

@Brian: tak, wyrażenia FOR / END I IF są makrami. Projekt SourceForge został całkowicie wdrożony. deButton utrzymuje sterowanie przyciskami. Gdy ma miejsce Dowolna akcja wprowadzania przez użytkownika, kod jest uruchamiany w trybie "control event", w którym deButton wykrywa, że został naciśnięty i oznacza, że został naciśnięty, zwracając TRUE. Tak więc " if (deButton(...)){... kod akcji ...} jest sposobem dołączania kodu akcji do przycisku, bez konieczności tworzenia zamknięcia lub pisania obsługi zdarzenia. Dd_throw jest sposobem zakończenia procesu, gdy akcja jest wykonywana, ponieważ operacja może mieć zmodyfikowane dane aplikacji, więc nie jest poprawne kontynuowanie procesu" control event " przez procedurę. Jeśli porównasz to do pisania programów obsługi zdarzeń, zapisuje to pisanie tych, i pozwala mieć dowolną liczbę kontrolek.

Dodany: Przepraszam, powinienem wyjaśnić, co mam na myśli przez słowo "utrzymuje". Po pierwszym uruchomieniu procedury (w trybie Pokaż) deButton tworzy kontrolkę przyciskową i zapamiętuje jej id w FIFO. Podczas kolejnych przejazdów (w trybie aktualizacji) deButton pobiera id z FIFO, modyfikuje je w razie potrzeby i umieszcza z powrotem w FIFO. W trybie kasowania odczytuje go z FIFO, niszczy i nie odkłada go z powrotem, przez co "śmieciarka" to. Tak więc deButton call zarządza całym okresem użytkowania kontrolki, utrzymując ją w zgodzie z danymi aplikacji, dlatego mówię, że "utrzymuje" ją.

Czwartym trybem jest EVENT (lub CONTROL). Gdy użytkownik wpisze znak lub kliknie przycisk, zdarzenie to jest przechwytywane i rejestrowane, a następnie procedura odkażania jest wykonywana w trybie zdarzenia. deButton pobiera id swojej kontrolki z FIFO i pyta, czy jest to kontrolka, która została kliknięta. Jeśli tak, to zwraca TRUE, aby kod akcji mógł zostać wykonany. Jeśli nie, to po prostu zwraca FALSE. Z drugiej strony deEdit(..., &myStringVar) wykrywa, czy zdarzenie było przeznaczone dla niego, a jeśli tak, przekazuje je do kontrolki edycji, a następnie kopiuje zawartość kontrolki edycji do myStringVar. Pomiędzy tym a normalnym przetwarzaniem aktualizacji, myStringVar zawsze równa się zawartości kontrolki edycji. Tak się robi" Wiązanie". To samo dotyczy pasków przewijania, list, pól combo, dowolnego rodzaju sterowania, które pozwala edytować aplikację data.

Oto link do mojej edycji Wikipedii: http://en.wikipedia.org/wiki/User:MikeDunlavey/Difex_Article

 90
Author: Mike Dunlavey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-05 12:32:20

Wykonanie różnicowe jest strategią zmiany przepływu kodu w oparciu o zdarzenia zewnętrzne. Zwykle odbywa się to poprzez manipulowanie strukturą danych w celu kroniki zmian. Jest to najczęściej używane w graficznych interfejsach użytkownika, ale jest również używane do takich rzeczy jak serializacja, gdzie scalasz zmiany do istniejącego stanu"."

Podstawowy przepływ jest następujący:

Start loop:
for each element in the datastructure: 
    if element has changed from oldDatastructure:
        copy element from datastructure to oldDatastructure
        execute corresponding subroutine (display the new button in your GUI, for example)
End loop:
Allow the states of the datastructure to change (such as having the user do some input in the GUI)

Zalety tego jest kilka. Po pierwsze, to separacja o wykonaniu twojego zmiany, a rzeczywisty manipulacja danymi wspierającymi. Co jest miłe dla wiele procesorów. Po drugie, zapewnia metodę niskiej przepustowości komunikowania zmian w programie.

 13
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-16 08:17:58

Pomyśl o tym, jak działa monitor:

Jest aktualizowany z częstotliwością 60 Hz-60 razy na sekundę. Migotanie migotanie migotanie 60 razy, ale twoje oczy są powolne i nie możnanaprawdę powiedzieć. Monitor pokazuje to, co znajduje się w buforze wyjściowym; po prostu przeciąga te dane co 1/60 sekundy, bez względu na to, co robisz.

Dlaczego chcesz, aby twój program aktualizował cały bufor 60 razy na sekundę, jeśli obraz nie powinien zmieniać się tak często? Co jeśli zmienisz tylko jeden piksel obrazek, czy należy przepisać cały bufor?


Jest to abstrakcja podstawowej idei: chcesz zmienić bufor wyjściowy w zależności od tego, jakie informacje mają być wyświetlane na ekranie. Chcesz zaoszczędzić jak najwięcej czasu procesora i czasu zapisu bufora, aby nie edytować części bufora, które nie muszą być zmieniane podczas następnego pullowania ekranu.

Monitor jest oddzielony od komputera i logiki (programów). Odczytuje z bufora wyjściowego z dowolną szybkością aktualizacji ekran. Chcemy, aby nasz komputer przestał niepotrzebnie synchronizować i przerysowywać. Możemy to rozwiązać zmieniając sposób pracy z buforem, co można zrobić na wiele sposobów. Jego technika implementuje kolejkę FIFO, która jest opóźniona -- przechowuje to, co właśnie wysłaliśmy do bufora. Opóźniona Kolejka FIFO nie przechowuje danych pikseli, przechowuje "podstawowe kształty" (które mogą być pikselami w aplikacji ,ale mogą to być również linie, prostokąty, łatwe do narysowania rzeczy, ponieważ są to tylko kształty, nie niepotrzebne dane są dozwolone).

Więc chcesz rysować / kasować rzeczy z ekranu? Nie ma sprawy. Bazując na zawartości kolejki FIFO wiem jak w tej chwili wygląda monitor. Porównuję moje pożądane wyjście (aby wymazać lub narysować nowe podstawowe) z kolejką FIFO i zmieniam tylko wartości, które wymagają zmiany / aktualizacji. Jest to krok, który nadaje mu nazwę ocena różnicowa.

Dwa różne sposoby, w których to doceniam:

Na Pierwszy: Mike Dunlavey używa rozszerzenia warunkowego. Kolejka FIFO zawiera wiele informacji ("poprzedni stan" lub bieżące rzeczy na monitorze lub czasowym urządzeniu ankietowym). Wszystko, co musisz dodać do tego, to stan, który chcesz wyświetlić na ekranie obok.

Bit warunkowy jest dodawany do każdego gniazda, które może pomieścić prymitywny w kolejce FIFO.

0 means erase
1 means draw

Mamy jednak poprzedni stan:

Was 0, now 0: don't do anything;
Was 0, now 1: add it to the buffer (draw it);
Was 1, now 1: don't do anything;
Was 1, now 0: erase it from the buffer (erase it from the screen);

Jest to eleganckie, ponieważ kiedy aktualizujesz coś, możesz naprawdę trzeba tylko wiedzieć, jakie prymitywy chcesz narysować na ekranie - to porównanie dowie się, czy powinno usunąć prymityw lub dodać / zachować go do / w buforze.

"Drugi": {]} To jest tylko jeden przykład, i myślę, że to, co Mike jest naprawdę się na coś, co powinno być fundamentalne w projektowaniu dla wszystkich projektów: zmniejszyć (obliczeniowe) złożoność projektowania, pisząc swoje najbardziej obliczeniowo intensywne operacje jako computerbrain-food lub tak blisko, jak można uzyskać. Szanuj naturalny czas działania urządzeń.

[4]}przerysowanie metody rysowania całego ekranu jest niezwykle kosztowne, a istnieją inne aplikacje, w których ten wgląd jest niezwykle cenny.

nigdy nie" przesuwamy " obiektów po ekranie. "Poruszanie się "jest kosztowną operacją, jeśli mamy zamiar naśladować fizyczne działanie" poruszania się", gdy projektujemy kod dla czegoś takiego jak monitor komputerowy. Zamiast tego obiekty po prostu migają i wyłączają się z monitorem. Za każdym razem, gdy obiekt się porusza, teraz jest to nowy zestaw prymitywów, a stary zestaw prymitywów miga.

Za każdym razem, gdy monitor wyciąga z bufora, mamy wpisy, które wyglądają jak

Draw bit    primitive_description
0           Rect(0,0,5,5);
1           Circ(0,0,2);
1           Line(0,1,2,5);

Obiekt nigdy nie wchodzi w interakcję z ekranem(lub czujnikiem czasu). Możemy poradzić sobie z tym bardziej inteligentnie niż Obiekt, gdy chciwie prosi o aktualizację całego ekranu, aby pokazać zmianę specyficzną tylko dla siebie.

Powiedzmy, że mamy listę wszystkich możliwych graficznych prymitywów naszego program jest w stanie generować, i że przywiązujemy każdą prymitywną do zbioru instrukcji warunkowych

if (iWantGreenCircle && iWantBigCircle && iWantOutlineOnMyCircle) ...

Oczywiście, jest to Abstrakcja i tak naprawdę zbiór warunkow, które reprezentują konkretną prymitywną istotę włączoną/wyłączoną, może być duży (być może setki flag, które muszą wszystkie Oceniać na prawdziwe).

Jeśli uruchomimy program, możemy rysować na ekranie z zasadniczo taką samą szybkością, z jaką możemy ocenić wszystkie te warunki. (Najgorszy przypadek: jak długo trwa ocena największy zbiór instrukcji warunkowych.)

Teraz, dla dowolnego stanu w programie, możemy po prostu ocenić wszystkie warunki i wyjść na ekran błyskawicznie! (znamy nasz kształt prymitywów i ich zależne if-twierdzenia.)

To byłoby jak zakup graficznie intensywnej gry. Tylko zamiast instalować ją na dysku twardym i uruchamiać przez procesor, kupujesz zupełnie nową płytę, która przechowuje całą grę i bierze za wejście: mysz, klawiatura, i bierze jako wyjście: monitor. Niezwykle skondensowana ocena warunkowa (jako najbardziej fundamentalną formą warunkową są bramki logiczne na płytkach drukowanych). Byłoby to oczywiście bardzo responsywne, ale nie oferuje prawie żadnego wsparcia w naprawianiu błędów, ponieważ cały projekt płytki zmienia się po wprowadzeniu drobnych zmian w projekcie (ponieważ "projekt" jest tak daleko od Natury płytki drukowanej). Kosztem elastyczności i jasności w sposobie wewnętrznego reprezentowania danych, które zdobyliśmy znaczna "responsywność", ponieważ nie robimy już" myślenia " w komputerze; to wszystko jest po prostu refleksem dla płytki drukowanej opartej na wejściach.

Lekcją, jak rozumiem, jest podział pracy w taki sposób, aby dać każdej części systemu (niekoniecznie tylko komputer i monitor) coś, co może zrobić dobrze. "Myślenie komputerowe" może być wykonywane w kategoriach pojęć takich jak przedmioty... Komputerowy mózg chętnie spróbuje to wszystko przemyśleć za ciebie, ale możesz uprość zadanie znacznie, jeśli jesteś w stanie pozwolić komputerowi myśleć w kategoriach data_update i conditional_evals. Nasze ludzkie abstrakcje pojÄ ™ Ä ‡ w kodzie sÄ ... idealistyczne, a w przypadku programĂłw wewnÄ ™ trznych metody rysujÄ ... nieco zbyt idealistyczne. Gdy wszystko, co chcesz, to wynik (tablica pikseli z poprawnymi wartościami kolorów) i masz maszynę, która może łatwo wypluć tablicę tak dużą co 1/60 sekundy, spróbuj wyeliminować jak najwięcej kwiecistego myślenia z komputera mózg, jak to możliwe, abyś mógł skupić się na tym, co naprawdę chcesz: synchronizować aktualizacje graficzne z Twoimi (szybkimi) wejściami i naturalnym zachowaniem monitora.

Jak to mapuje do innych aplikacji? Chciałbym usłyszeć inne przykłady, ale jestem pewien, że jest ich wiele. Myślę, że wszystko, co zapewnia w czasie rzeczywistym "okno" do stanu informacji (stan zmiennej lub coś w rodzaju bazy danych... monitor jest tylko oknem do bufora wyświetlacza) może skorzystać z tych spostrzeżeń.

 11
Author: sova,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-04 04:11:39

Uważam to pojęcie za bardzo podobne do maszyn państwowych klasycznej elektroniki cyfrowej. Szczególnie te, które pamiętają swoją poprzednią pracę.

Maszyna, której następne wyjście zależy od bieżącego wejścia i poprzedniego wyjścia zgodnie z (twój kod tutaj). Obecne wejście to nic innego jak poprzednie wyjście + (użytkownik, interakcja tutaj).

Wypełnij powierzchnię takimi maszynami, a będzie ona interaktywna dla użytkownika i jednocześnie będzie stanowić warstwę zmiennych danych. Ale w tym etap będzie nadal głupi, tylko odzwierciedlając interakcję użytkownika z bazowymi danymi.

Następnie połącz maszyny na swojej powierzchni, pozwól im udostępniać notatki, zgodnie z (twój kod tutaj), a teraz uczynimy go inteligentnym. Stanie się interaktywnym systemem obliczeniowym.

Więc wystarczy podać swoją logikę w dwóch miejscach w powyższym modelu; resztą zajmuje się sam projekt maszyny. I to jest w tym dobre.

 3
Author: wingman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-04 04:03:52