std :: lock_guard จะเร็วกว่า std :: mutex :: lock () ได้อย่างไร?


9

ฉันโต้เถียงกับเพื่อนร่วมงานเกี่ยวกับ lock_guard และเขาเสนอว่า lock_guard นั้นน่าจะช้ากว่า mutex :: lock () / mutex :: unlock () เนื่องจากราคาของ instantiate และทำให้ชั้น lock_guard ลดลง

จากนั้นฉันก็สร้างการทดสอบอย่างง่ายและแปลกใจรุ่นที่มี lock_guard นั้นเร็วกว่ารุ่นที่มี 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;
}

ผลลัพธ์ในเครื่องของฉัน:

Take: 41 ms
Take: 22 ms

บางคนสามารถอธิบายได้ว่าเหตุใดจึงเป็นเช่นนี้


2
และคุณวัดผลของคุณกี่ครั้ง
artm

7
โปรดโพสต์แฟล็กคอมไพเลอร์ของคุณ ... การเปรียบเทียบจะขึ้นอยู่กับระดับการเพิ่มประสิทธิภาพ ...
Macmade

10
เคล็ดลับสำหรับมืออาชีพ: เมื่อทำการวัดเช่นนี้ให้สลับลำดับเพื่อให้แน่ใจว่าไม่ใช่เพียงข้อมูล / คำแนะนำที่เป็นสาเหตุของปัญหา: coliru.stacked-crooked.com/a/81f75a1ab52cb1cc
NathanOliver

2
อีกสิ่งหนึ่งที่มีประโยชน์เมื่อทำการวัดเช่นนี้: ใส่สิ่งของทั้งหมดในลูปที่ใหญ่ขึ้นเพื่อให้คุณรันชุดการวัดทั้งหมดพูด 20 ครั้งในการวิ่งแต่ละครั้ง โดยปกติแล้วการวัดในภายหลังจะเป็นสิ่งที่มีความหมายจริง ๆ เพราะจากนั้นแคชได้ตัดสินลงในพฤติกรรมใดก็ตามที่มีแนวโน้มว่าจะเกิดขึ้นในระยะยาว
Mark Phaedrus

2
แม้ว่าจะstd::lock_guardช้าลงเล็กน้อยเว้นแต่คุณจะสามารถพิสูจน์ได้ว่ามันสำคัญในแง่ของประสิทธิภาพการเพิ่มความเร็วนั้นจะไม่ทำให้ผลประโยชน์อื่น ๆ ของการใช้std::lock_guard(ส่วนใหญ่ RAII) เป็นโมฆะ หากg++เป็นสิ่งที่สามารถโยนหรืออะไรก็ตามที่อาจเปลี่ยนเป็นสิ่งที่อาจซับซ้อนกว่าในอนาคตคุณเกือบจะต้องใช้วัตถุบางอย่างในการเป็นเจ้าของล็อค
François Andrieux

คำตอบ:


6

บิลด์รีลีสสร้างผลลัพธ์เดียวกันสำหรับทั้งสองเวอร์ชัน

การDEBUGสร้างแสดงเวลานานขึ้น ~ 33% สำหรับfunc2; ความแตกต่างที่ผมเห็นในการถอดชิ้นส่วนที่func2ใช้และจะเรียก__security_cookie@_RTC_CheckStackVars@8

คุณมีเวลาบั๊กหรือไม่

แก้ไข: นอกจากนี้ในขณะที่ดูการRELEASEถอดชิ้นส่วนฉันสังเกตเห็นว่าmutexวิธีการที่ถูกบันทึกไว้ในสองรีจิสทรี:

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

และเรียกวิธีเดียวกันจากทั้งสองfunc1และfunc2:

010F1067  call        edi  
....
010F107F  call        ebx  
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.