Bluebird의 util.toFastProperties 함수는 객체의 속성을 어떻게 "빠르게" 만듭니까?
Bluebird의 파일에는 다음과 같은 기능이 있습니다.
function toFastProperties(obj) {
/*jshint -W027*/
function f() {}
f.prototype = obj;
ASSERT("%HasFastProperties", true, obj);
return f;
eval(obj);
}
무슨 이유에서인지 리턴 함수 뒤에 문이 있는데, 왜 거기에 있는지 잘 모르겠습니다.
또한 저자가 이에 대한 JS힌트의 경고를 잠재웠기 때문에 의도적인 것으로 보입니다.
'return' 후 'eval'에 연결할 수 없습니다. (W027)
이 기능은 정확히 무엇을 합니까? 있습니까?util.toFastProperties
정말로 물체의 속성을 "비활성화"시키는 것입니까?
Bluebird의 GitHub 저장소에서 소스 코드에 대한 의견이나 문제 목록에 대한 설명을 검색했지만 찾을 수 없었습니다.
2017년 업데이트:먼저, 오늘 오신 독자분들을 위해 - 여기 노드 7(4+)과 함께 작동하는 버전이 있습니다.
function enforceFastProperties(o) {
function Sub() {}
Sub.prototype = o;
var receiver = new Sub(); // create an instance
function ic() { return typeof receiver.foo; } // perform access
ic();
ic();
return o;
eval("o" + o); // ensure no dead code elimination
}
하나 또는 두 개의 작은 최적화를 실행합니다. 아래의 모든 것은 여전히 유효합니다.
먼저 무엇을 하는지, 왜 그것이 더 빠른지, 그리고 왜 그것이 작동하는지에 대해 논의해 보겠습니다.
기능
V8 엔진은 두 가지 객체 표현을 사용합니다.
다음은 속도 차이를 보여주는 간단한 데모입니다.여기서는 다음을 사용합니다.delete
개체를 느린 사전 모드로 강제 전환하는 문입니다.
엔진은 가능할 때마다, 그리고 일반적으로 많은 속성 액세스가 수행될 때마다 고속 모드를 사용하려고 하지만 때로는 사전 모드로 전환되기도 합니다.사전 모드에 있으면 성능 저하가 크기 때문에 일반적으로 개체를 빠른 모드로 전환하는 것이 좋습니다.
이 해킹은 사전 모드에서 개체를 고속 모드로 강제 전환하기 위한 것입니다.
- 블루버드의 페트카는 여기서 그것에 대해 이야기합니다.
- 뱌체슬라프 에고로프의 이 슬라이드(웨이백 머신)도 그것을 언급합니다.
- "*https://stackoverflow.com/questions/23455678/pros-and-cons-of-dictionary-mode* " 질문과 수락된 답변도 관련이 있습니다.
- 이 약간 오래된 기사는 v8에서 개체를 저장하는 방법에 대해 좋은 아이디어를 제공할 수 있는 상당히 좋은 자료입니다.
더 빠른 이유
JavaScript에서 프로토타입은 일반적으로 많은 인스턴스 간에 공유되는 기능을 저장하며 동적으로 많이 변경되는 경우는 거의 없습니다.이러한 이유로 함수를 호출할 때마다 추가 패널티를 피하기 위해 빠른 모드로 설정하는 것이 매우 바람직합니다.
이를 위해 - v8은 기꺼이 다음과 같은 객체를 넣을 것입니다..prototype
생성자로서 함수를 호출하여 생성된 모든 개체에 의해 공유되기 때문에 빠른 모드에서 함수의 속성.이는 일반적으로 현명하고 바람직한 최적화입니다.
작동 방식
먼저 코드를 살펴보고 각 라인이 수행하는 작업을 알아보겠습니다.
function toFastProperties(obj) {
/*jshint -W027*/ // suppress the "unreachable code" error
function f() {} // declare a new function
f.prototype = obj; // assign obj as its prototype to trigger the optimization
// assert the optimization passes to prevent the code from breaking in the
// future in case this optimization breaks:
ASSERT("%HasFastProperties", true, obj); // requires the "native syntax" flag
return f; // return it
eval(obj); // prevent the function from being optimized through dead code
// elimination or further optimizations. This code is never
// reached but even using eval in unreachable code causes v8
// to not optimize functions.
}
v8이 이러한 최적화를 수행한다고 주장하기 위해 코드를 직접 찾을 필요는 없습니다. 대신 v8 유닛 테스트를 읽을 수 있습니다.
// Adding this many properties makes it slow.
assertFalse(%HasFastProperties(proto));
DoProtoMagic(proto, set__proto__);
// Making it a prototype makes it fast again.
assertTrue(%HasFastProperties(proto));
이 테스트를 읽고 실행하면 이 최적화가 v8에서 실제로 작동한다는 것을 알 수 있습니다.하지만 - 방법을 보면 좋을 것입니다.
우리가 확인하면,objects.cc
다음 함수(L9925)를 찾을 수 있습니다.
void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
if (object->IsGlobalObject()) return;
// Make sure prototypes are fast objects and their maps have the bit set
// so they remain fast.
if (!object->HasFastProperties()) {
MigrateSlowToFast(object, 0);
}
}
지금이다,JSObject::MigrateSlowToFast
Dictionary를 사용하여 빠른 V8 개체로 변환합니다.v8 객체 내부에 대한 읽을 가치가 있고 흥미로운 통찰력이지만 여기서는 주제가 아닙니다.v8 개체에 대해 배울 수 있는 좋은 방법이기 때문에 여기서 읽어보시기를 여전히 적극 권장합니다.
우리가 체크아웃하면,SetPrototype
objects.cc
우리는 그것이 12231 라인에서 불리는 것을 볼 수 있습니다.
if (value->IsJSObject()) {
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
}
그 다음에는 다음과 같이 부릅니다.FuntionSetPrototype
그것이 우리가 얻는 것입니다..prototype =
.
하고있다__proto__ =
또는.setPrototypeOf
또한 작동했을 수도 있지만 이것들은 ES6 기능이고 Bluebird는 Netscape 7 이후 모든 브라우저에서 실행되므로 코드를 단순화하는 것은 불가능합니다.를 들어,가 를들어확우, 인다면한가리예,▁we면▁check다를 선택하면,.setPrototypeOf
다음을 확인할 수:
// ES6 section 19.1.2.19.
function ObjectSetPrototypeOf(obj, proto) {
CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");
if (proto !== null && !IS_SPEC_OBJECT(proto)) {
throw MakeTypeError("proto_object_or_null", [proto]);
}
if (IS_SPEC_OBJECT(obj)) {
%SetPrototype(obj, proto); // MAKE IT FAST
}
return obj;
}
로위있는것에바에 것.Object
:
InstallFunctions($Object, DONT_ENUM, $Array(
...
"setPrototypeOf", ObjectSetPrototypeOf,
...
));
그래서 우리는 페트카가 쓴 암호에서 맨 메탈로 가는 길을 걸었습니다.너무 좋았어요.
고지 사항:
이는 모두 구현 세부사항입니다.Petka와 같은 사람들은 최적화 괴짜입니다.항상 조기 최적화가 97%의 시간 동안 모든 악의 근원이라는 것을 기억하십시오.Bluebird는 매우 기본적인 작업을 매우 자주 수행하므로 이러한 성능 해킹으로부터 많은 것을 얻을 수 있습니다. 콜백만큼 빠른 것은 쉽지 않습니다.라이브러리에 전원을 공급하지 않는 코드에서는 이러한 작업을 수행할 필요가 거의 없습니다.
V8 개발자입니다.받아들여진 대답은 훌륭한 설명입니다. 저는 단지 한 가지를 강조하고 싶었습니다. 이른바 "빠른"과 "느린" 부동산 모드는 불행하게도 잘못된 이름입니다. 각각 장단점이 있습니다.다음은 다양한 작업의 성능에 대한 (약간 간소화된) 개요입니다.
구조물과 유사한 특성 | 사전 속성 | |
---|---|---|
개체에 속성 추가 | -- |
+ |
속성 삭제 | --- |
+ |
속성 읽기/쓰기, 처음으로 | - |
+ |
읽기/쓰기, 캐시, 단모형 | +++ |
+ |
읽기/쓰기, 캐시됨, 몇 개의 모양 | ++ |
+ |
읽기/쓰기, 캐시, 다양한 모양 | -- |
+ |
구어명 | "빠른" | "느림" |
보시다시피 사전 속성은 실제로 이 표에 있는 대부분의 행에 대해 더 빠릅니다. 사용자가 무엇을 하든 상관하지 않고 모든 것을 확실한(기록을 깨는 것은 아니지만) 성능으로 처리하기 때문입니다.구조와 유사한 속성은 한 가지 특정 상황(코드의 모든 개별 위치에서 고유한 개체 모양을 거의 볼 수 없는 기존 속성의 값 읽기/쓰기)에 대해 빠르게 증가하고 있지만, 이에 대한 대가로 다른 모든 작업, 특히 속성을 추가하거나 제거하는 작업이 훨씬 느려집니다.
우연히 구조적 특성이 큰 이점을 갖는 특별한 경우(+++
앱의하며, 이 에 "별명을 되었습니다는 특히 빈번하고 많은 앱의 성능에 매우 중요하며, 이 때문에 "빠른"이라는 별명을 얻었습니다.하지만 중요한 것은 당신이 당신을 사랑할 때delete
속성과 V8은 영향을 받는 객체를 사전 모드로 전환합니다. 그러면 그것은 멍청해지거나 짜증을 내려고 하는 것이 아닙니다. 오히려 그것은 당신이 하고 있는 일에 최고의 성능을 제공하려고 합니다.과거에는 적절한 시기에 더 많은 개체를 사전("느림") 모드로 더 빨리 전환하여 상당한 성능 향상을 달성한 패치를 랜딩했습니다.
객체가 일반적으로 구조적 속성의 혜택을 받을 수도 있지만, 코드가 V8에서 사전 속성으로 전환하는 경우에는 취소해야 합니다. Bluebird도 그런 경우가 있습니다.그래도 그 이름은toFastProperties
그것의 단순성에 있어서 약간 오해의 소지가 있습니다; 더 정확한 (비록 다루기 힘들지만) 이름은.spendTimeOptimizingThisObjectAssumingItsPropertiesWontChange
이는 작업 자체가 비용이 많이 든다는 것을 의미하며, 특정 제한된 경우에만 의미가 있습니다.만약 누군가가 결론을 취소했다면, "오, 이것은 훌륭합니다, 그래서 저는 지금 기꺼이 속성을 삭제할 수 있습니다, 그리고 그냥 전화하세요.toFastProperties
그 후 매번"라는 메시지가 표시되면 큰 오해가 되어 성능이 상당히 저하될 수 있습니다.
몇 가지 간단한 경험칙을 고수한다면, 내부 객체 표현을 강제로 변경하려고 할 이유조차 없습니다.
- 생성자를 사용하고 생성자의 모든 속성을 초기화합니다.(이는 엔진뿐만 아니라 코드의 이해 가능성과 유지 관리 가능성에도 도움이 됩니다.TypeScript는 엔지니어링 생산성에 도움이 되기 때문에 TypeScript가 이를 강제하지는 않지만 강력하게 장려한다는 점을 고려해 보십시오.
- 클래스 또는 프로토타입을 사용하여 메소드를 설치합니다. 각 개체 인스턴스에 메소드만 적용하지 마십시오. (이 방법은 여러 가지 이유로 일반적인 모범 사례입니다. 그 중 하나는 속도가 더 빠르다는 것입니다.)
- 하다를 .
delete
속성이 왔다 갔다 할 때, 사용하는 것을 선호합니다.Map
ES5 시대의 "지도로서의 객체" 패턴 위에.상태로 될 수 부울( 동등한) 개가특상정을또전전나거수환환태다되있될로부경동니선호울합한우등는)을 합니다.o.has_state = true; o.has_state = false;
속성을 및 합니다. 표시기 속성을 추가 및 삭제합니다. - 성능에 관한 한, 측정, 측정, 측정.성능 향상을 위한 시간 단축을 시작하기 전에 앱을 프로파일링하여 핫스팟이 어디에 있는지 확인합니다.더 빠르게 변화를 구현할 수 있는 경우 실제 앱(또는 10줄 마이크로 벤치마크가 아닌 매우 가까운 앱)으로 실제로 도움이 되는지 확인합니다.
마지막으로, 팀장님이 "'빠른' 속성과 '느린' 속성이 있다고 들었다"고 말씀하실 경우, 우리의 속성이 모두 '빠른' 속성인지 확인한 후, 이 게시물을 가리킵니다:-)
2021년 이후의 현실(NodeJS 버전 12 이상).엄청난 최적화가 이루어진 것처럼 보이지만, 필드가 삭제되고 배열이 희박한 개체는 느려지지 않습니다.아니면 내가 smth를 놓쳤나요?
// run in Node with enabled flag
// node --allow-natives-syntax script.js
function Point(x, y) {
this.x = x;
this.y = y;
}
var obj1 = new Point(1, 2);
var obj2 = new Point(3, 4);
delete obj2.y;
var arr = [1,2,3]
arr[100] = 100
console.log('obj1 has fast properties:', %HasFastProperties(obj1));
console.log('obj2 has fast properties:', %HasFastProperties(obj2));
console.log('arr has fast properties:', %HasFastProperties(arr));
둘 다 진실을 보여줍니다.
obj1 has fast properties: true
obj2 has fast properties: true
arr has fast properties: true
// run in Node with enabled flag
// node --allow-natives-syntax script.js
function Point(x, y) {
this.x = x;
this.y = y;
}
var obj2 = new Point(3, 4);
console.log('obj has fast properties:', %HasFastProperties(obj2)) // true
delete obj2.y;
console.log('obj2 has fast properties:', %HasFastProperties(obj2)); //true
var obj = {x : 1, y : 2};
console.log('obj has fast properties:', %HasFastProperties(obj)) //true
delete obj.x;
console.log('obj has fast properties:', %HasFastProperties(obj)); //fasle
기능과 객체가 다르게 보입니다.
언급URL : https://stackoverflow.com/questions/24987896/how-does-bluebirds-util-tofastproperties-function-make-an-objects-properties
'source' 카테고리의 다른 글
jQuery를 사용하여 자리 표시자 텍스트 변경 (0) | 2023.08.10 |
---|---|
#1093 표 '표'는 '삭제' 대상과 별도의 데이터 소스로 2회 지정 (0) | 2023.08.10 |
A의의 높이방법는 ▁how법A의의 높이방법는 ▁how법A의의 높이방법는 ▁how법??? (0) | 2023.08.10 |
OnItemClickListener가 목록 보기에서 작동하지 않음 (0) | 2023.08.10 |
데이터베이스 링크를 통해 설명하시겠습니까? (0) | 2023.08.10 |