나는 C의 ++ 응용 프로그램에 루비 2.2를 내장하고 toRubyString
특정 사용 사례에 출력 프로파일 런타임을 지배 밝혀졌다어떻게 나중에 재사용 할 수 있도록 Ruby VALUE 값을 캐시 할 수 있습니까?
VALUE toRubyString(const MyObject &o)
{
const char *utf8 = get_string_rep_of(o);
return rb_enc_str_new(utf8, strlen(utf8), rb_utf8_encoding());
}
형태의 기능을 최적화하기 위해 노력하고 있습니다. 이 경우 함수는 매우 자주 호출되지만 값은 MyObject
입니다. 따라서, 내 생각은 내가
std::map<MyObject, VALUE> cache;
VALUE toRubyString(const MyObject &o)
{
std::map<MyObject, VALUE>::const_iterator it = cache.find(o);
if (it != cache.end()) {
return it->second;
}
const char *utf8 = get_string_rep_of(o);
VALUE v = rb_enc_str_new(utf8, strlen(utf8), rb_utf8_encoding());
cache[o] = v;
return v;
}
아아의 라인을 따라, 다시 사용할 수 있도록 같은 std::map<MyObject, VALUE>
나에 VALUE
값을 캐시하는 것입니다,이 수정과 함께, 루비 인터프리터가 결국 충돌 것을 발견하고, return it->second;
줄을 생략하면 충돌이 사라집니다 (즉, 코드가 캐시 된 항목을 재사용하지 않을 때).
나는 단지 도움이되지 않았다 (캐시에 VALUE
를 추가하기 전에) 몇 후 천 함수를 호출하지만, 심지어
rb_gc_mark(v);
전화를 발생하기 때문에이 가비지 컬렉터 관련이 의심 . 아무도 내가 여기에서 놓칠 수도있는 것에 관해서 어떤 생각을 가지고 있습니까?
중요한 질문은 소유권입니다. 당신이 사용하고있는 리소스를 정리할 책임이있는 사람은'v'와'utf8'입니까? 'v'는이 함수가 끝난 후에도'utf8'에 의존합니까? (다른 두 개의 작은 메모 : 속도에 대해 염려하고 있으므로'std :: map' 대신에'std :: unordered_map'을 사용하는 것을 고려하십시오 - O (1) 대 O (log N) 검색 시간입니다. 맵에 포인터/ref가 아닌 값으로'MyObject'를 넣으면 복사본을 만들 수 있습니다. 괜찮을 지 모르지만 값이 비싸거나 맵을 일치시키지 못하는 경우가 있습니다. std :: map'이 계산됩니다.) – metal
@metal 저는 이것이 소유권 문제라고 생각합니다 (Ruby GC가 여기에 관련되어 있다고 생각하는 이유입니다). 'utf8'에 의해 지시 된 데이터의 소유권은'get_string_rep_of'와 함께 남아 있습니다. 'rb_enc_str_new'는 소유권을 가지지 않고 데이터 복사본을 만듭니다. VALUE 값에 관해서는 Ruby가 소유권을 관리하는 방법을 잘 모르겠지만 어떤 경우에도 명시적인 참조 계산이없는 것 같습니다. –
또 다른 대안은 Ruby에서 값을 캐시하는 것입니다. 즉, toRubyString을 메모 방법으로 만드는 것입니다. 아마 약간 성능이 떨어지지 만 더 안정적으로 보입니다. 그러나 어떤 경우 든 해시 키는 무엇인가 (이것은 C++ 솔루션에도 적용됩니다). 당신이 선호하는 것처럼 객체 ID를 사용한다면, 객체의 문자열 표현이 바뀌는 것을 알 수 없을 것입니다. – user1934428