Làm thế nào std :: lock_guard có thể nhanh hơn std :: mutex :: lock ()?


9

Tôi đã tranh cãi với một đồng nghiệp, về lock_guard, và anh ấy đề xuất rằng lock_guard chậm hơn đáng kể so với mutex :: lock () / mutex :: Unlock () do chi phí khởi tạo và hủy liên kết khóa lock_guard.

Sau đó, tôi đã tạo ra thử nghiệm đơn giản này và thật ngạc nhiên, phiên bản có lock_guard nhanh hơn gần hai lần so với phiên bản có mutex :: lock () / mutex :: unlock ()

#include <iostream>
#include <mutex>
#include <chrono>

std::mutex m;
int g = 0;

void func1()
{
    m.lock();
    g++;
    m.unlock();
}

void func2()
{
    std::lock_guard<std::mutex> lock(m);
    g++;
}

int main()
{
    auto t = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000; i++)
    {
        func1();
    }

    std::cout << "Take: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - t).count() << " ms" << std::endl;

    t = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000; i++)
    {
        func2();
    }

    std::cout << "Take: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - t).count() << " ms" << std::endl;

    return 0;
}

Kết quả trên máy của tôi:

Take: 41 ms
Take: 22 ms

Ai đó có thể làm rõ tại sao và làm thế nào điều này có thể được?


2
và bạn đã đo bao nhiêu lần?
artm

7
Vui lòng gửi cờ trình biên dịch của bạn ... Điểm chuẩn sẽ phụ thuộc vào mức độ tối ưu hóa ...
Maccraft

10
Mẹo chuyên nghiệp: Khi thực hiện các phép đo như thế này, hãy trao đổi thứ tự để đảm bảo rằng đó không chỉ là dữ liệu / hướng dẫn lạnh gây ra sự cố: coliru.stacked-crooking.com/a/81f75a1ab52cb1cc
NathanOliver

2
Một điều khác hữu ích khi thực hiện các phép đo như thế này: đặt toàn bộ vào một vòng lặp lớn hơn, để bạn chạy toàn bộ bộ đo, giả sử, 20 lần mỗi lần chạy. Thông thường các phép đo sau này sẽ là các phép đo thực sự có ý nghĩa, bởi vì sau đó bộ đệm đã giải quyết thành bất kỳ hành vi nào mà nó có thể có trong thời gian dài.
Mark Phaedrus

2
Ngay cả khi std::lock_guardchậm hơn một chút, trừ khi bạn có thể chứng minh rằng nó quan trọng về hiệu suất, tốc độ tăng sẽ không làm mất hiệu lực các lợi ích khác của việc sử dụng std::lock_guard(chủ yếu là RAII). Nếu g++bất cứ thứ gì có thể ném hoặc bất cứ thứ gì có thể thay đổi thành thứ gì đó có khả năng phức tạp hơn trong tương lai, bạn gần như phải sử dụng một số loại đối tượng để sở hữu khóa.
François Andrieux

Câu trả lời:


6

Bản dựng phát hành tạo ra kết quả giống nhau cho cả hai phiên bản.

Bản DEBUGdựng cho thấy thời gian dài hơn ~ 33% func2; sự khác biệt tôi thấy trong việc tháo gỡ func2sử dụng __security_cookievà gọi @_RTC_CheckStackVars@8.

Bạn đang định thời gian DEBUG?

EDIT: Ngoài ra, trong khi xem xét việc RELEASEtháo gỡ, tôi nhận thấy rằng mutexcác phương thức đã được lưu trong hai đăng ký:

010F104E  mov         edi,dword ptr [__imp___Mtx_lock (010F3060h)]  
010F1054  xor         esi,esi  
010F1056  mov         ebx,dword ptr [__imp___Mtx_unlock (010F3054h)]  

và được gọi theo cùng một cách từ cả hai func1func2:

010F1067  call        edi  
....
010F107F  call        ebx  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.