차등 실행은 어떻게 작동합니까?


83

Stack Overflow에서 이에 대한 몇 가지 언급을 보았지만 Wikipedia (관련 페이지가 삭제 된 이후로 삭제됨)와 MFC 동적 대화 데모에서 나를 깨우쳐주지 못했습니다. 누군가 이것을 설명해 주시겠습니까? 근본적으로 다른 개념을 배우는 것은 좋은 것 같습니다.


답변을 바탕으로 : 나는 그것에 대해 더 나은 느낌을 받고 있다고 생각합니다. 처음에는 소스 코드를 충분히주의 깊게 보지 않은 것 같습니다. 나는이 시점에서 차등 실행에 대해 엇갈린 감정을 가지고있다. 한편으로는 특정 작업을 상당히 쉽게 만들 수 있습니다. 반면에, 그것을 시작하고 실행 (즉, 선택한 언어로 설정)하는 것은 쉽지 않습니다 (내가 더 잘 이해하면 될 것입니다). 한 번만 만든 다음 필요에 따라 확장하면됩니다. 정말로 이해하기 위해서는 다른 언어로 구현 해봐야 할 것 같습니다.


3
관심을 가져 주셔서 감사합니다. 나에게는 단순한 것이 실망스러워 보이는 것이 흥미 롭다. 나에게 가장 예쁜 것은 단순하다. 조심해.
Mike Dunlavey

1
중요한 것을 놓치고 있다고 생각합니다. 지금 저는 "이것은 간단합니다."라고 생각하고 있습니다. 정말로 이해했다면 "간단하고 정말 놀랍고 유용합니다."라고 생각할 것입니다.
Brian

6
... 나는 여전히 사람들이 MVC를 가장 위대한 것이라고 생각하는 것을보고 있으며, 나는 그것을 다시해야하기보다는 은퇴하는 것이 더 낫다고 생각한다.
Mike Dunlavey

1
... "실행 취소"를 위해 데이터를 직렬화 / 역 직렬화하고 둘 중 XOR 인 파일을 스핀 오프합니다.이 파일은 대부분 0이므로 쉽게 압축됩니다. 이를 사용하여 이전 데이터를 복구하십시오. 이제 임의의 데이터 구조로 일반화하십시오.
Mike Dunlavey

1
워크로드에 @MikeDunlavey를 추가하고 싶지는 않지만 놓친 경우 Source Forge는 의심스러운 비즈니스 관행으로 은혜에서 떨어졌습니다. Github.com은 요즘 멋진 아이들이 어울리는 곳입니다. 그들은에서 W7에 대한 정말 좋은 Windows 클라이언트가 desktop.github.com
교수 팔켄

답변:


95

이런, 브라이언, 당신의 질문을 더 일찍 봤으면 좋았을 텐데요. (좋든 나쁘 든) 거의 나의 "발명품"이기 때문에 도움을 드릴 수있을 것입니다.

삽입 됨 : 내가 할 수있는 가장 짧은 설명은 정상적인 실행이 공을 공중에 던지고 잡는 것과 같으면 차등 실행은 저글링과 같다는 것입니다.

@windfinder의 설명이 나와 다르며 괜찮습니다. 이 기술은 머리를 감싸는 것이 쉽지 않으며, 작동하는 설명을 찾는 데 약 20 년이 걸렸습니다. 여기에 또 다른 기회를 드리겠습니다.

  • 뭐야?

우리 모두는 컴퓨터가 프로그램을 따라 가며 입력 데이터를 기반으로 조건부 분기를 수행하고 작업을 수행하는 간단한 아이디어를 이해합니다. (단순한 구조화 된 goto-less, return-less 코드 만 처리한다고 가정합니다.)이 코드에는 일련의 명령문, 기본 구조화 된 조건, 단순 루프 및 서브 루틴 호출이 포함됩니다. (지금은 값을 반환하는 함수는 잊어 버리세요.)

이제 동일한 코드를 서로 잠금 단계에서 실행하고 메모를 비교할 수있는 두 대의 컴퓨터를 상상해보십시오. 컴퓨터 1은 입력 데이터 A로 실행되고 컴퓨터 2는 입력 데이터 B로 실행됩니다. 이들은 단계별로 나란히 실행됩니다. IF (test) .... ENDIF와 같은 조건문이 나오면 테스트가 참인지에 대한 의견이 다르면 거짓이면 테스트를 말하는 사람이 ENDIF로 건너 뛰고 기다립니다. 따라 잡을 여동생. (이것이 코드가 구조화 된 이유이므로 자매가 결국 ENDIF에 도달 할 것이라는 것을 알고 있습니다.)

두 컴퓨터가 서로 대화 할 수 있기 때문에 메모를 비교하고 두 입력 데이터 세트와 실행 이력이 어떻게 다른지 자세히 설명 할 수 있습니다.

물론 차등 실행 (DE)에서는 한 대의 컴퓨터로 두 대를 시뮬레이션합니다.

이제 한 세트의 입력 데이터 만 가지고 있지만 그것이 시간 1에서 시간 2로 어떻게 변경되었는지 확인하고 싶다고 가정합니다. 실행중인 프로그램이 직렬 변환기 / 역 직렬 변환기라고 가정합니다. 실행할 때 현재 데이터를 직렬화 (쓰기)하고 과거 데이터 (마지막으로 기록한 데이터)를 역 직렬화 (읽기)합니다. 이제 지난번 데이터와 이번 데이터의 차이점을 쉽게 확인할 수 있습니다.

쓰고있는 파일과 읽고있는 이전 파일이 함께 큐 또는 FIFO (선입 선출)를 구성하지만 이는 매우 깊은 개념이 아닙니다.

  • 무엇에 좋은가요?

그래픽 프로젝트에서 작업하는 동안 사용자가 "기호"라고하는 작은 디스플레이 프로세서 루틴을 구성 할 수있었습니다.이 루틴은 파이프, 탱크, 밸브 등의 다이어그램과 같은 것을 페인트하기 위해 더 큰 루틴으로 조립할 수 있습니다. 전체 다이어그램을 다시 그릴 필요없이 자체적으로 점진적으로 업데이트 할 수 있다는 점에서 다이어그램을 "동적"으로 만들고 싶었습니다. (하드웨어는 오늘날의 표준에 비해 느 렸습니다.) 저는 (예를 들어) 막대 차트 막대를 그리는 루틴이 이전 높이를 기억하고 점차적으로 자체적으로 업데이트 할 수 있다는 것을 깨달았습니다.

이것은 OOP처럼 들리지 않습니까? 그러나 "개체"를 "만들기"보다는 다이어그램 프로 시저의 실행 순서에 대한 예측 가능성을 활용할 수 있습니다. 막대의 높이를 순차적 인 바이트 스트림으로 쓸 수 있습니다. 그런 다음 이미지를 업데이트하기 위해 다음 업데이트 단계를 준비하기 위해 새 매개 변수를 쓰는 동안 이전 매개 변수를 순차적으로 읽는 모드에서 프로 시저를 실행할 수 있습니다.

이것은 어리석은 것처럼 보이며 절차에 조건이 포함 되 자마자 중단되는 것처럼 보입니다. 왜냐하면 새 스트림과 이전 스트림이 동기화되지 않기 때문입니다. 그러나 조건부 테스트의 부울 값도 직렬화하면 동기화 상태로 돌아갈 수 있다는 사실이 나에게 떠 올랐습니다 . 간단한 규칙 ( "지우기 모드 규칙")을 준수 한다면 이것이 항상 효과 가 있다는 것을 스스로 확신하고 증명하는 데 시간이 걸렸 습니다.

결과적으로 사용자는 디스플레이가 아무리 복잡하거나 구조적으로 변하더라도 동적으로 업데이트되는 방식에 대해 걱정할 필요없이 이러한 "동적 기호"를 디자인하고 더 큰 다이어그램으로 조합 할 수 있습니다.

그 당시에는 시각적 개체 간의 간섭에 대해 걱정해야했기 때문에 하나를 지워도 다른 개체가 손상되지 않습니다. 그러나 이제는 Windows 컨트롤에서이 기술을 사용하고 Windows에서 렌더링 문제를 처리하도록합니다.

그래서 그것은 무엇을 성취합니까? 즉, 컨트롤을 그리는 절차를 작성하여 대화 상자를 만들 수 있으며 실제로 컨트롤 개체를 기억하거나 점진적으로 업데이트하거나 조건에 따라 표시 / 사라짐 / 이동하는 것에 대해 걱정할 필요가 없습니다. 그 결과 대화 소스 코드가 훨씬 더 작고 단순 해졌으며, 동적 레이아웃, 컨트롤 수 변경, 컨트롤 배열 또는 그리드 등은 사소한 일입니다. 또한 편집 필드와 같은 컨트롤은 편집중인 응용 프로그램 데이터에 간단하게 바인딩 될 수 있으며 항상 정확할 것이므로 이벤트를 처리 할 필요가 없습니다. 응용 프로그램 문자열 변수에 대한 편집 필드를 입력하는 것은 한 줄 편집입니다.

  • 이해하기 어려운 이유는 무엇입니까?

제가 가장 설명하기 어려운 것은 소프트웨어에 대해 다르게 생각해야한다는 것입니다. 프로그래머는 소프트웨어의 객체-액션 뷰에 너무 굳게 결합되어 객체가 무엇인지, 클래스가 무엇인지, 디스플레이를 "구축"하는 방법, 이벤트를 처리하는 방법을 알고 싶어합니다. 폭탄을 터뜨리는 것입니다. 제가 전달하고자하는 것은 정말로 중요한 것은 무엇을 말해야 하는가라는 것입니다."여기에서 변수 A, 거기에서 변수 B, 아래에서 변수 C를 편집하고 싶다"라고 말하면 DSL (domain-specific language)을 구축하고 있다고 상상해보십시오. 그러면 마법처럼 처리됩니다. . 예를 들어, Win32에는 대화 상자를 정의하기위한이 "자원 언어"가 있습니다. 충분히 멀리 가지 않는 것을 제외하고는 완벽하게 좋은 DSL입니다. 기본 절차 언어에 "살아 있지"거나 이벤트를 처리하거나 루프 / 조건 / 서브 루틴을 포함하지 않습니다. 그러나 그것은 의미가 있으며 Dynamic Dialogs는 작업을 완료하려고합니다.

따라서 다른 사고 방식은 다음과 같습니다. 프로그램을 작성하려면 먼저 적절한 DSL을 찾고 (또는 발명) 가능한 한 많은 프로그램을 코딩합니다. 하자 단지 구현을 위하여 존재하는 모든 객체와 작업을 처리합니다.

차등 실행을 실제로 이해하고 사용하려면 몇 가지 까다로운 문제가 있습니다. 한때 Lisp 매크로로 코딩 했는데,이 까다로운 부분이 사용자를 위해 처리 될 수 있지만 "일반"언어에서는 함정을 피하기 위해 프로그래머 규율이 필요합니다.

너무 길어서 죄송합니다. 내가 말이 안된다면 지적 해 주시면 고맙게 생각하고 고칠 수 있습니다.

추가 :

에서 자바 스윙 , TextInputDemo라는 예제 프로그램이있다. 270 줄 (50 개 상태 목록 제외)을 사용하는 정적 대화 상자입니다. 동적 대화 상자 (MFC)에서는 약 60 줄입니다.

#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."));
}

추가 :

다음은 약 40 줄의 코드로 병원 환자 배열을 편집하는 예제 코드입니다. 1-6 행은 "데이터베이스"를 정의합니다. 10-23 행은 UI의 전체 내용을 정의합니다. 30-48 행은 단일 환자의 기록을 편집하기위한 컨트롤을 정의합니다. 프로그램의 형태는 마치 디스플레이를 한 번만 만드는 것처럼 제 시간에 이벤트를 거의 알리지 않습니다. 그런 다음 주제가 추가 또는 제거되거나 다른 구조적 변경이 발생하면 DE가 대신 증분 업데이트를 수행한다는 점을 제외하고는 처음부터 다시 생성되는 것처럼 간단히 다시 실행됩니다. 장점은 프로그래머가 UI의 점진적 업데이트를 수행하기 위해주의를 기울이거나 코드를 작성할 필요가 없으며 정확하다는 것입니다. 이 재실행이 성능 문제로 보일 수 있지만 그렇지 않습니다.

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 }

추가됨 : Brian이 좋은 질문을했고 그 대답은 여기 본문에 있다고 생각했습니다.

@Mike : "if (deButton (50, 20,"Add ")) {"문이 실제로 무엇을하는지 명확하지 않습니다. deButton 기능은 무엇을합니까? 또한 FOR / END 루프가 일종의 매크로 등을 사용하고 있습니까? – 브라이언.

@Brian : 예, FOR / END 및 IF 문은 매크로입니다. SourceForge 프로젝트에는 완전한 구현이 있습니다. deButton은 버튼 컨트롤을 유지합니다. 사용자 입력 동작이 발생하면 코드는 "control event"모드에서 실행됩니다. 여기서 deButton은 눌 렸음을 감지하고 TRUE를 반환하여 눌렀 음을 나타냅니다. 따라서 "if (deButton (...)) {... 액션 코드 ...}는 클로저를 만들거나 이벤트 핸들러를 작성할 필요없이 버튼에 액션 코드를 첨부하는 방법입니다. DD_THROW는 작업이 응용 프로그램 데이터를 수정했을 수 있으므로 작업이 수행 될 때 패스를 종료하는 방법이므로 루틴을 통해 "제어 이벤트"전달을 계속하는 것은 유효하지 않습니다. 이것을 이벤트 핸들러 작성과 비교하면 작성하는 시간을 절약 할 수 있습니다. 그리고 그것은 당신이 제어의 수를 가질 수 있습니다.

추가됨 : 죄송합니다. "유지"라는 단어가 의미하는 바를 설명해야합니다. 프로 시저가 처음 실행될 때 (SHOW 모드에서), deButton은 버튼 컨트롤을 생성하고 FIFO에서 해당 ID를 기억합니다. 후속 패스 (UPDATE 모드에서)에서 deButton은 FIFO에서 ID를 가져 와서 필요한 경우 수정 한 다음 FIFO에 다시 넣습니다. ERASE 모드에서는 FIFO에서 읽어서 파괴하고 다시 넣지 않으므로 "가비지 수집"을 수행합니다. 따라서 deButton 호출은 컨트롤의 전체 수명을 관리하여 응용 프로그램 데이터와 일치하도록 유지합니다. 이것이 바로 "유지 관리"라고 말하는 이유입니다.

네 번째 모드는 EVENT (또는 CONTROL)입니다. 사용자가 문자를 입력하거나 버튼을 클릭하면 해당 이벤트를 포착하여 기록한 다음 EVENT 모드에서 deContents 프로 시저를 실행합니다. deButton은 FIFO에서 버튼 컨트롤의 ID를 가져오고 이것이 클릭 된 컨트롤인지 묻습니다. 그렇다면 TRUE를 반환하므로 액션 코드를 실행할 수 있습니다. 그렇지 않으면 FALSE를 반환합니다. 반면에는 deEdit(..., &myStringVar)이벤트가 해당 이벤트인지 감지하고, 그렇다면 편집 컨트롤로 전달한 다음 편집 컨트롤의 내용을 myStringVar에 복사합니다. 이 처리와 일반 UPDATE 처리 사이에서 myStringVar는 항상 편집 컨트롤의 내용과 동일합니다. 이것이 "바인딩"이 수행되는 방법입니다. 스크롤 막대, 목록 상자, 콤보 상자, 응용 프로그램 데이터를 편집 할 수있는 모든 종류의 컨트롤에도 동일한 개념이 적용됩니다.

내 Wikipedia 편집에 대한 링크는 다음과 같습니다. http://en.wikipedia.org/wiki/User:MikeDunlavey/Difex_Article


4
답변으로 괴롭혀서 미안하지만 내가 이것을 올바르게 이해하면 기본적으로 계산을 프로세서에 더 가깝고 출력 하드웨어에서 멀리 이동시키는 것입니다. 이것은 우리가 객체와 변수로 프로그래밍함으로써 동일한 출력을 얻기 위해 최고의 기계 코드로 매우 쉽게 변환된다는 아이디어에 많은 재고를 투자하기 때문에 놀라운 통찰력입니다. 컴파일 할 때 코드를 최적화 할 수 있지만 시간에 따른 작업은 최적화 할 수 없습니다. 시간 의존성을 거부하고 프리미티브가 작업을 수행 하도록하십시오 !
sova

2
@Joey : 이제 FIFO에서 실행되는 제어 구조와 작업 대기열에서 실행되는 병렬 코 루틴에 대한 아이디어에 대해 언급 했으므로 공통점이 많습니다.
Mike Dunlavey

2
Differential Execution이 react.js 라이브러리에서 사용하는 접근 방식에 얼마나 가까운 지 궁금합니다.
Brian

2
@Brian : 정보를 훑어 보는 것에서 react.js는 diff 함수를 사용하여 증분 업데이트를 브라우저에 보냅니다. diff 함수가 실제로 차동 실행만큼 가능한지 알 수 없습니다. 임의의 변경을 처리 할 수 ​​있고 바인딩을 단순화한다고 주장합니다. 그것이 같은 정도로했는지는 모르겠습니다. 어쨌든 올바른 방향이라고 생각합니다. 여기에 몇 개의 동영상이 있습니다.
Mike Dunlavey 2014 년

2
@MikeDunlavey, 저는 OpenGL / IMGUI와 Model, Model-View 및 View 레이어에 대한 반응 형 프로그래밍의 조합으로 도구를 작성합니다. 지금은 이전 스타일로 돌아 가지 않을 것입니다. 동영상 링크에 감사드립니다.
Cthutu

13

차등 실행은 외부 이벤트를 기반으로 코드 흐름을 변경하기위한 전략입니다. 이것은 일반적으로 변경 사항을 기록하기 위해 일종의 데이터 구조를 조작하여 수행됩니다. 이것은 대부분 그래픽 사용자 인터페이스에서 사용되지만 기존 "상태"에 변경 사항을 병합하는 직렬화와 같은 작업에도 사용됩니다.

기본 흐름은 다음과 같습니다.

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)

이것의 장점은 몇 가지입니다. 하나는 변경 실행과 지원 데이터의 실제 조작을 분리하는 것입니다. 다중 프로세서에 적합합니다. 둘째, 프로그램의 변경 사항을 전달하는 낮은 대역폭 방법을 제공합니다.


12

모니터가 어떻게 작동하는지 생각해보십시오.

60Hz-초당 60 회 업데이트됩니다. 플리커 플리커 플리커 60 배, 그러나 당신의 눈은 느리고 수 없습니다 정말 말한다. 모니터는 출력 버퍼에있는 모든 것을 보여줍니다. 당신이 무엇을하든 1/60 초마다이 데이터를 끌어옵니다.

이제 이미지가 그렇게 자주 변경되지 않아야하는데 왜 프로그램이 초당 60 번 전체 버퍼를 업데이트하기를 원합니까? 이미지의 한 픽셀 만 변경하면 전체 버퍼를 다시 작성해야합니까?


이것은 기본 개념의 추상화입니다. 화면에 표시 할 정보에 따라 출력 버퍼를 변경하려고합니다. 가능한 한 많은 CPU 시간과 버퍼 쓰기 시간을 절약하기를 원하므로 다음 화면 풀을 위해 변경할 필요가없는 버퍼 부분을 편집하지 마십시오.

모니터는 컴퓨터 및 로직 (프로그램)과 분리되어 있습니다. 화면을 업데이트하는 속도에 관계없이 출력 버퍼에서 읽습니다. 우리는 컴퓨터가 불필요하게 동기화 및 다시 그리기를 중지하기를 원합니다. 버퍼 작업 방식을 변경하여이 문제를 해결할 수 있으며, 다양한 방법으로 수행 할 수 있습니다. 그의 기술은 지연되는 FIFO 대기열을 구현합니다. 이것은 우리가 방금 버퍼로 보낸 것을 보관합니다. 지연된 FIFO 대기열은 픽셀 데이터를 보유하지 않고 "모양 기본 요소"를 보유합니다 (애플리케이션의 픽셀 일 수 있지만 선, 직사각형, 그리기 쉬운 물건 일 수도 있습니다. 모양 일 뿐이며 불필요한 데이터는 없습니다. 허용).

화면에서 무언가를 그리거나 지우고 싶습니까? 문제 없어요. FIFO 대기열의 내용을 기반으로 현재 모니터가 어떻게 보이는지 알고 있습니다. 원하는 출력 (새 기본 요소를 지우거나 그리기 위해)을 FIFO 대기열과 비교하고 변경 / 업데이트해야하는 값만 변경합니다. 이것은 차동 평가라는 이름을 부여하는 단계입니다.

내가 이것을 감사하는 두 가지 뚜렷한 방법 :

첫 번째 : Mike Dunlavey는 조건문 확장을 사용합니다. FIFO 대기열에는 많은 정보 ( "이전 상태"또는 모니터 또는 시간 기반 폴링 장치의 현재 항목)가 포함되어 있습니다. 여기에 추가해야 할 것은 다음 화면에 표시하려는 상태입니다.

FIFO 큐에 프리미티브를 보유 할 수있는 모든 슬롯에 조건부 비트가 추가됩니다.

0 means erase
1 means draw

그러나 이전 상태가 있습니다.

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);

무언가를 업데이트 할 때 화면에 그리려는 프리미티브 만 알면되므로이 비교는 프리미티브를 지우거나 버퍼에 추가 / 유지해야하는지 알아낼 것입니다.

두 번째 : 이것은 단지 하나의 예일뿐입니다. Mike가 실제로 얻고있는 것은 모든 프로젝트의 설계에서 기본이되어야한다고 생각합니다. 가장 계산이 많은 작업을 컴퓨터 브레인 푸드로 작성하여 설계의 (계산적) 복잡성을 줄이십시오. 또는 최대한 가깝습니다. 장치의 자연스러운 타이밍을 존중하십시오.

전체 화면을 그리는 다시 그리기 방법은 엄청나게 많은 비용이 들며이 통찰력이 매우 가치있는 다른 응용 프로그램이 있습니다.

우리는 화면에서 물체를 "움직이지"않습니다. "이동"은 컴퓨터 모니터와 같은 코드를 디자인 할 때 "이동"의 물리적 동작을 모방하려는 경우 비용이 많이 드는 작업입니다. 대신 개체는 기본적으로 모니터와 함께 깜박입니다. 오브젝트가 움직일 때마다 새로운 프리미티브 세트가되고 이전 프리미티브 세트가 깜박입니다.

모니터가 버퍼에서 가져올 때마다 다음과 같은 항목이 있습니다.

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

개체가 화면 (또는 시간에 민감한 폴링 장치)과 상호 작용하지 않습니다. 개체가 자신에게만 특정한 변경 사항을 표시하기 위해 전체 화면을 업데이트하도록 탐욕스럽게 요청할 때보 다 지능적으로 처리 할 수 ​​있습니다.

프로그램이 생성 할 수있는 모든 가능한 그래픽 프리미티브 목록이 있고 각 프리미티브를 조건문 세트에 연결한다고 가정 해 보겠습니다.

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

물론 이것은 추상화이며 실제로는 특정 프리미티브가 켜짐 / 꺼짐을 나타내는 조건부 세트가 클 수 있습니다 (아마도 모두 참으로 평가되어야하는 수백 개의 플래그).

프로그램을 실행하면이 모든 조건을 평가할 수있는 동일한 속도로 화면에 그릴 수 있습니다. (최악의 경우 : 가장 큰 조건문 집합을 평가하는 데 걸리는 시간)

이제 프로그램의 모든 상태에 대해 간단하게 모든 조건을 평가하고 화면에 출력 할 수 있습니다 .(우리는 우리의 형태 프리미티브와 종속 if 문을 알고 있습니다.)

이것은 그래픽 집약적 인 게임을 사는 것과 같습니다. HDD에 설치하고 프로세서를 통해 실행하는 대신, 게임 전체를 수용하고 마우스, 키보드, 출력 (모니터)으로 사용하는 새로운 보드를 구입합니다. 엄청나게 압축 된 조건부 평가 (가장 기본적인 조건부 형태는 회로 기판의 논리 게이트입니다). 이것은 당연히 응답 성이 매우 높지만, 작은 디자인 변경을 수행 할 때 전체 보드 디자인이 변경되기 때문에 버그 수정에 거의 지원을 제공하지 않습니다 ( "디자인"이 회로 보드의 특성에서 너무 멀리 떨어져 있기 때문입니다. ). 내부적으로 데이터를 표현하는 방법의 유연성과 명료성을 희생시키면서 우리는 더 이상 컴퓨터에서 "사고"를하지 않기 때문에 상당한 "대응력"을 얻었습니다. 입력을 기반으로 한 회로 기판 용.

내가 이해하는 교훈은 시스템의 각 부분 (반드시 컴퓨터와 모니터가 아닌)이 잘 할 수있는 것을 주도록 노동을 나누는 것입니다. "컴퓨터 사고"는 사물과 같은 개념으로 할 수 있습니다 ... 컴퓨터 두뇌는이 모든 것을 기꺼이 시도하고 생각할 것입니다.하지만 컴퓨터가 생각하게 할 수 있다면 작업을 상당히 단순화 할 수 있습니다. data_update 및 conditional_evals 조건. 인간의 개념을 코드로 추상화하는 것은 이상 주의적이며 내부 프로그램 그리기 방법의 경우 지나치게 이상 주의적입니다. 원하는 것은 결과 (정확한 색상 값을 가진 픽셀 배열)이고 쉽게 있는 기계가있을 때 1/60 초마다 큰 배열을 뱉어 내고 컴퓨터 두뇌에서 가능한 한 많은 꽃 생각을 제거하여 정말로 원하는 것에 집중할 수 있도록 노력하십시오 : 그래픽 업데이트를 (빠른) 입력과 동기화하고 모니터의 자연스러운 동작.

이것은 다른 응용 프로그램에 어떻게 매핑됩니까? 다른 예를 듣고 싶지만 많은 것이 있다고 확신합니다. 정보 상태 (변수 상태 또는 데이터베이스와 같은 것 ... 모니터는 디스플레이 버퍼에 대한 창)에 실시간 "창"을 제공하는 모든 것이 이러한 통찰력으로부터 혜택을받을 수 있다고 생각합니다.


2
++ 당신의 의견에 감사드립니다. 저에게 처음에는 느린 장치 (9600-baud 원격 텍스트 터미널)에서 프로그램 설명 디스플레이를 수행하려는 시도였습니다. 기본적으로 자동 비교를 수행하고 최소한의 업데이트를 전송합니다. 그런 다음 무차별 대입으로 이것을 코딩하지 않는 이유에 대해 압박을 받았습니다. 대답 : 코드의 표면 형태가 단순한 페인트 처럼 보이면 더 짧고 버그가 거의 없기 때문에 개발 시간의 일부에 완료됩니다. (이것이 DSL의 장점이라고 생각합니다.)
Mike Dunlavey

... 해방 된 개발 노력은 사용자가 반응적이고 만족스러워하는보다 정교하고 역동적 인 디스플레이에 다시 투자 할 수 있습니다. 따라서 개발자 비용으로 더 많은 UI를 얻을 수 있습니다.
Mike Dunlavey


1
이것은 당신이 컴퓨터 게임에 대해 이야기했을 때 이해하게했습니다. 실제로 많은 게임은 Mike가 사용자 인터페이스를 수행하는 방식과 같이 코딩됩니다. 모든 프레임에서 순환되는 업데이트 목록입니다.
Prof. Falken 2015 년

당신이 말한 것 중 일부와 관련된 겉보기에는 키 / 버튼이 눌려 있는지 또는 방금 놓았는지 감지하는 것입니다. 버튼을 눌렀는지 여부를 쉽게 알 수 있습니다. 저수준 API의 참 / 거짓 값입니다. 키가 눌려 있는지 확인하려면 이전에 어떤 상태인지 알아야합니다. 0-> 1이면 그냥 눌린 것입니다. 1-> 1이면 누르고 있고, 1-> 0이면 방금 놓은 것입니다.
Joshua Hedges

3

이 개념은 고전적인 디지털 전자 장치의 상태 기계와 매우 유사합니다. 특히 이전 출력을 기억하는 사람들.

다음 출력이 (YOUR CODE HERE)에 따라 현재 입력 및 이전 출력에 따라 달라지는 기계. 이 현재 입력은 이전 출력 + (USER, INTERACT HERE) 일뿐입니다.

이러한 기계로 표면을 채우면 사용자가 상호 작용할 수 있으며 동시에 변경 가능한 데이터 레이어를 나타냅니다. 그러나이 단계에서는 사용자 상호 작용을 기본 데이터에 반영하는 것만으로도 여전히 멍청 할 것입니다.

다음으로, 표면에있는 기계를 서로 연결하고 (여기에있는 코드)에 따라 메모를 공유하도록하세요. 이제 우리는 지능적으로 만듭니다. 인터랙티브 컴퓨팅 시스템이 될 것입니다.

따라서 위 모델의 두 위치에서 논리를 제공하면됩니다. 나머지는 기계 설계 자체에 의해 처리됩니다. 그것이 좋은 점입니다.


1
이 문제가 발생했을 때 염두에 두었던 하드웨어 모델을 기억하는 것 같습니다.
Mike Dunlavey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.