trả lời đến Q # 1
Nếu các con trỏ thường là nhanh hơn và tôi đã đã chia sẻ con trỏ những tùy chọn nào để tôi có để gọi một phương pháp mà các điểm trỏ được chia sẻ tới?
operator->
trong boost::shared_ptr
has assertion:
typename boost::detail::sp_member_access<T>::type operator->() const
{
BOOST_ASSERT(px != 0);
return px;
}
Vì vậy, trước hết, hãy chắc chắn rằng bạn có NDEBUG
định (thường là trong phiên bản xây dựng nó được thực hiện tự động):
#define NDEBUG
Tôi đã thực hiện so sánh lắp ráp giữa hội nghị truyền thông của boost::shared_ptr
và con trỏ liệu:
template<int tag,typename T>
NOINLINE void test(const T &p)
{
volatile auto anti_opti=0;
ASM_MARKER<tag+0>();
anti_opti = p->data;
anti_opti = p->data;
ASM_MARKER<tag+1>();
(void)anti_opti;
}
test<1000>(new Foo);
ASM
mã của test
khi T
là Foo*
được (đừng sợ, tôi có diff
dưới đây):
_Z4testILi1000EP3FooEvRKT0_:
.LFB4088:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdi, %rbx
subq $16, %rsp
.cfi_def_cfa_offset 32
movl $0, 12(%rsp)
call _Z10ASM_MARKERILi1000EEvv
movq (%rbx), %rax
movl (%rax), %eax
movl %eax, 12(%rsp)
movl %eax, 12(%rsp)
call _Z10ASM_MARKERILi1001EEvv
movl 12(%rsp), %eax
addq $16, %rsp
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
test<2000>(boost::make_shared<Foo>());
ASM
mã của test
khi T
là boost::shared_ptr<Foo>
:
_Z4testILi2000EN5boost10shared_ptrI3FooEEEvRKT0_:
.LFB4090:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
movq %rdi, %rbx
subq $16, %rsp
.cfi_def_cfa_offset 32
movl $0, 12(%rsp)
call _Z10ASM_MARKERILi2000EEvv
movq (%rbx), %rax
movl (%rax), %eax
movl %eax, 12(%rsp)
movl %eax, 12(%rsp)
call _Z10ASM_MARKERILi2001EEvv
movl 12(%rsp), %eax
addq $16, %rsp
.cfi_def_cfa_offset 16
popq %rbx
.cfi_def_cfa_offset 8
ret
.cfi_endproc
Dưới đây là đầu ra của diff -U 0 foo_p.asm shared_ptr_foo_p.asm
lệnh:
--- foo_p.asm Fri Apr 12 10:38:05 2013
+++ shared_ptr_foo_p.asm Fri Apr 12 10:37:52 2013
@@ -1,2 +1,2 @@
-_Z4testILi1000EP3FooEvRKT0_:
-.LFB4088:
+_Z4testILi2000EN5boost10shared_ptrI3FooEEEvRKT0_:
+.LFB4090:
@@ -11 +11 @@
-call _Z10ASM_MARKERILi1000EEvv
+call _Z10ASM_MARKERILi2000EEvv
@@ -16 +16 @@
-call _Z10ASM_MARKERILi1001EEvv
+call _Z10ASM_MARKERILi2001EEvv
Như bạn có thể thấy, sự khác biệt là chỉ trong chữ ký chức năng, và tag
phi -giá trị đối số mẫu, mã còn lại là IDENTICAL
.
Nói chung - số đếm tham chiếu được đồng bộ hóa giữa các chủ đề (thường thông qua hoạt động nguyên tử). Thay vào đó, nếu bạn sử dụng boost::intrusive_ptr
, thì bạn có thể triển khai increment
/decrement
của riêng mình mà không cần đồng bộ hóa luồng, điều này sẽ tăng tốc độ tính tham chiếu.
Nếu bạn có thể đủ khả năng sử dụng unique_ptr
hoặc di chuyển ngữ nghĩa (qua Boost.Move hoặc C++ 11) - thì sẽ không có bất kỳ tính tham chiếu nào - nó sẽ nhanh hơn nữa.
LIVE DEMO WITH ASM OUTPUT
#define NDEBUG
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#define NOINLINE __attribute__ ((noinline))
template<int>
NOINLINE void ASM_MARKER()
{
volatile auto anti_opti = 11;
(void)anti_opti;
}
struct Foo
{
int data;
};
template<int tag,typename T>
NOINLINE void test(const T &p)
{
volatile auto anti_opti=0;
ASM_MARKER<tag+0>();
anti_opti = p->data;
anti_opti = p->data;
ASM_MARKER<tag+1>();
(void)anti_opti;
}
int main()
{
{
auto p = new Foo;
test<1000>(p);
delete p;
}
{
test<2000>(boost::make_shared<Foo>());
}
}
trả lời đến Q # 2
Tôi có một phương pháp dụ (s) đang nhanh chóng được gọi là tạo ra một std :: vector trên stack mỗi lần.
Nói chung, bạn nên cố gắng sử dụng lại khả năng của vector
để tránh phân bổ lại tốn kém.Ví dụ nó là tốt hơn để thay thế:
{
for(/*...*/)
{
std::vector<value> temp;
// do work on temp
}
}
với:
{
std::vector<value> temp;
for(/*...*/)
{
// do work on temp
temp.clear();
}
}
Nhưng hình như do gõ std::map<std::string,std::vector<std::string>*>
bạn đang cố gắng để phí phạm một số loại memoization.
Như đã gợi ý, thay vì std::map
trong đó có O (ln (N)) tra cứu/chèn bạn có thể thử sử dụng boost::unordered_map
/std::unordered_map
trong đó có O (1) trung bình và O (N) tồi tệ nhất trường hợp phức tạp cho tra cứu/chèn, và địa phương/compactess tốt hơn (bộ nhớ cache thân thiện).
Ngoài ra, cosider thử Boost.Flyweight:
Flyweights là quy mô nhỏ lớp xử lý cấp quyền truy cập thường xuyên để dữ liệu chung chung, do đó cho phép cho việc quản lý một lượng lớn các đơn vị nằm trong giới hạn bộ nhớ hợp lý. Boost.Flyweight giúp dễ dàng sử dụng thành ngữ lập trình phổ biến này bằng cách cung cấp mẫu lớp trọng số, hoạt động như một bản thay thế cho const T.
Donald Knuth: "Chúng ta nên quên hiệu quả nhỏ, khoảng 97% thời gian: tối ưu hóa sớm là gốc của tất cả" => hồ sơ xấu đầu tiên, xác định các điểm nóng, tối ưu hóa ** những **. –