Java เร็วกว่า 8 เท่าด้วยอาร์เรย์มากกว่า std :: vector ใน C ++ ผมทำอะไรผิด?


88

ฉันมีโค้ด Java ต่อไปนี้พร้อมอาร์เรย์ขนาดใหญ่หลายอันซึ่งไม่เคยเปลี่ยนขนาด มันทำงานใน 1100 ms บนคอมพิวเตอร์ของฉัน

ผมนำมาใช้รหัสเดียวกันใน C ++ std::vectorและใช้

เวลาของการใช้งาน C ++ ซึ่งรันโค้ดเดียวกันคือ 8800 ms บนคอมพิวเตอร์ของฉัน ฉันทำอะไรผิดถึงได้ทำงานช้าขนาดนี้

โดยทั่วไปโค้ดจะทำสิ่งต่อไปนี้:

for (int i = 0; i < numberOfCells; ++i) {
        h[i] =  h[i] + 1;
        floodedCells[i] =  !floodedCells[i];
        floodedCellsTimeInterval[i] =  !floodedCellsTimeInterval[i];
        qInflow[i] =  qInflow[i] + 1;
}

มันวนซ้ำผ่านอาร์เรย์ต่างๆที่มีขนาดประมาณ 20,000

คุณสามารถค้นหาการใช้งานทั้งสองได้ภายใต้ลิงก์ต่อไปนี้:

(ใน ideone ฉันสามารถวิ่งวนซ้ำได้เพียง 400 ครั้งแทนที่จะเป็น 2,000 ครั้งเนื่องจากข้อ จำกัด ด้านเวลา แต่ถึงแม้จะมีความแตกต่างกันถึงสามครั้ง)


42
std::vector<bool>ใช้หนึ่งบิตต่อองค์ประกอบเพื่อประหยัดพื้นที่ซึ่งนำไปสู่การขยับบิตจำนวนมาก หากคุณต้องการความเร็วคุณควรอยู่ห่างจากมัน ใช้std::vector<int>แทน
molbdnilo

44
@molbdnilo หรือ std :: vector <char> ไม่จำเป็นต้องเสียมากขนาดนั้น ;-)
ฟาน

7
สนุกพอ เวอร์ชัน c ++ เร็วขึ้นเมื่อจำนวนเซลล์ 200 ตำแหน่งแคช?
กัปตันยีราฟ

9
ส่วนที่ II: คุณจะดีกว่ามากในการสร้างคลาส / โครงสร้างแยกต่างหากที่มีหนึ่งในสมาชิกแต่ละตัวของอาร์เรย์จากนั้นมีอาร์เรย์ของอ็อบเจ็กต์เดียวของโครงสร้างนี้เนื่องจากคุณจะทำซ้ำผ่านหน่วยความจำเพียงครั้งเดียวใน ทิศทางเดียว.
Timo Geusch

9
@TimoGeusch: ในขณะที่ฉันคิดว่าh[i] += 1;หรือ (ยังดีกว่า) ++h[i]อ่านได้มากกว่าh[i] = h[i] + 1;แต่ฉันค่อนข้างแปลกใจที่เห็นความแตกต่างอย่างมีนัยสำคัญในความเร็วระหว่างพวกเขา คอมไพเลอร์สามารถ "คิดออก" ได้ว่าทั้งคู่กำลังทำสิ่งเดียวกันและสร้างโค้ดเดียวกันไม่ว่าจะด้วยวิธีใดก็ตาม (อย่างน้อยก็ในกรณีส่วนใหญ่)
Jerry Coffin

คำตอบ:


36

นี่คือเวอร์ชัน C ++ ที่มีข้อมูลต่อโหนดที่รวบรวมเป็นโครงสร้างและใช้เวกเตอร์เดียวของโครงสร้างนั้น:

#include <vector>
#include <cmath>
#include <iostream>



class FloodIsolation {
public:
  FloodIsolation() :
      numberOfCells(20000),
      data(numberOfCells)
  {
  }
  ~FloodIsolation(){
  }

  void isUpdateNeeded() {
    for (int i = 0; i < numberOfCells; ++i) {
       data[i].h = data[i].h + 1;
       data[i].floodedCells = !data[i].floodedCells;
       data[i].floodedCellsTimeInterval = !data[i].floodedCellsTimeInterval;
       data[i].qInflow = data[i].qInflow + 1;
       data[i].qStartTime = data[i].qStartTime + 1;
       data[i].qEndTime = data[i].qEndTime + 1;
       data[i].lowerFloorCells = data[i].lowerFloorCells + 1;
       data[i].cellLocationX = data[i].cellLocationX + 1;
       data[i].cellLocationY = data[i].cellLocationY + 1;
       data[i].cellLocationZ = data[i].cellLocationZ + 1;
       data[i].levelOfCell = data[i].levelOfCell + 1;
       data[i].valueOfCellIds = data[i].valueOfCellIds + 1;
       data[i].h0 = data[i].h0 + 1;
       data[i].vU = data[i].vU + 1;
       data[i].vV = data[i].vV + 1;
       data[i].vUh = data[i].vUh + 1;
       data[i].vVh = data[i].vVh + 1;
       data[i].vUh0 = data[i].vUh0 + 1;
       data[i].vVh0 = data[i].vVh0 + 1;
       data[i].ghh = data[i].ghh + 1;
       data[i].sfx = data[i].sfx + 1;
       data[i].sfy = data[i].sfy + 1;
       data[i].qIn = data[i].qIn + 1;


      for(int j = 0; j < nEdges; ++j) {
        data[i].flagInterface[j] = !data[i].flagInterface[j];
        data[i].typeInterface[j] = data[i].typeInterface[j] + 1;
        data[i].neighborIds[j] = data[i].neighborIds[j] + 1;
      }
    }

  }

private:

  const int numberOfCells;
  static const int nEdges = 6;
  struct data_t {
    bool floodedCells = 0;
    bool floodedCellsTimeInterval = 0;

    double valueOfCellIds = 0;
    double h = 0;

    double h0 = 0;
    double vU = 0;
    double vV = 0;
    double vUh = 0;
    double vVh = 0;
    double vUh0 = 0;
    double vVh0 = 0;
    double ghh = 0;
    double sfx = 0;
    double sfy = 0;
    double qInflow = 0;
    double qStartTime = 0;
    double qEndTime = 0;
    double qIn = 0;
    double nx = 0;
    double ny = 0;
    double floorLevels = 0;
    int lowerFloorCells = 0;
    bool floorCompleteleyFilled = 0;
    double cellLocationX = 0;
    double cellLocationY = 0;
    double cellLocationZ = 0;
    int levelOfCell = 0;
    bool flagInterface[nEdges] = {};
    int typeInterface[nEdges] = {};
    int neighborIds[nEdges] = {};
  };
  std::vector<data_t> data;

};

int main() {
  std::ios_base::sync_with_stdio(false);
  FloodIsolation isolation;
  clock_t start = clock();
  for (int i = 0; i < 400; ++i) {
    if(i % 100 == 0) {
      std::cout << i << "\n";
    }
    isolation.isUpdateNeeded();
  }
  clock_t stop = clock();
  std::cout << "Time: " << difftime(stop, start) / 1000 << "\n";
}

ตัวอย่างสด

ตอนนี้เวลาคือ 2x ของความเร็วของเวอร์ชัน Java (846 เทียบกับ 1631)

อัตราต่อรองคือ JIT สังเกตเห็นการเผาไหม้แคชของการเข้าถึงข้อมูลทั่วทุกที่และเปลี่ยนรหัสของคุณให้เป็นลำดับที่คล้ายกันเชิงตรรกะ แต่มีประสิทธิภาพมากขึ้น

ฉันยังปิดการซิงโครไนซ์ stdio ด้วยเนื่องจากจำเป็นเฉพาะเมื่อคุณผสมprintf/ scanfกับ C ++ std::coutและstd::cin. ในขณะที่เกิดขึ้นคุณจะพิมพ์ค่าเพียงไม่กี่ค่า แต่พฤติกรรมเริ่มต้นของ C ++ สำหรับการพิมพ์นั้นหวาดระแวงและไม่มีประสิทธิภาพมากเกินไป

ถ้าnEdgesไม่ใช่ค่าคงที่จริงค่า "อาร์เรย์" 3 ค่าจะต้องถูกตัดออกจากstruct. นั่นไม่ควรทำให้เกิดผลงานที่ยอดเยี่ยม

คุณอาจได้รับการเพิ่มประสิทธิภาพอื่น ๆ โดยการจัดเรียงค่าในนั้นstructโดยการลดขนาดซึ่งจะช่วยลดการใช้หน่วยความจำ (และจัดเรียงการเข้าถึงเช่นกันเมื่อไม่สำคัญ) แต่ฉันไม่แน่ใจ

หลักการง่ายๆคือการพลาดแคชเพียงครั้งเดียวมีราคาแพงกว่าคำสั่ง 100 เท่า การจัดเรียงข้อมูลของคุณให้มีการเชื่อมโยงกันของแคชนั้นมีค่ามากมาย

หากการจัดเรียงข้อมูลใหม่เป็น a structไม่สามารถทำได้คุณสามารถเปลี่ยนการวนซ้ำของคุณให้อยู่เหนือแต่ละคอนเทนเนอร์ได้

นอกจากนี้โปรดทราบว่าเวอร์ชัน Java และ C ++ มีความแตกต่างเล็กน้อยในเวอร์ชันเหล่านี้ สิ่งที่ฉันเห็นคือเวอร์ชัน Java มี 3 ตัวแปรในลูป "สำหรับแต่ละขอบ" ในขณะที่ C ++ มีเพียง 2 เท่านั้นฉันทำให้ของฉันตรงกับ Java ผมไม่รู้ว่ามีคนอื่น


44

ใช่แคชในเวอร์ชัน c ++ ใช้เวลาในการตอก ดูเหมือนว่า JIT จะพร้อมที่จะจัดการสิ่งนี้ได้ดีกว่า

ถ้าคุณเปลี่ยนด้านนอก forใน isUpdateNeeded () เป็นส่วนย่อยที่สั้นกว่า ความแตกต่างออกไป

ตัวอย่างด้านล่างสร้างความเร็ว 4x

void isUpdateNeeded() {
    for (int i = 0; i < numberOfCells; ++i) {
        h[i] =  h[i] + 1;
        floodedCells[i] =  !floodedCells[i];
        floodedCellsTimeInterval[i] =  !floodedCellsTimeInterval[i];
        qInflow[i] =  qInflow[i] + 1;
        qStartTime[i] =  qStartTime[i] + 1;
        qEndTime[i] =  qEndTime[i] + 1;
    }

    for (int i = 0; i < numberOfCells; ++i) {
        lowerFloorCells[i] =  lowerFloorCells[i] + 1;
        cellLocationX[i] =  cellLocationX[i] + 1;
        cellLocationY[i] =  cellLocationY[i] + 1;
        cellLocationZ[i] =  cellLocationZ[i] + 1;
        levelOfCell[i] =  levelOfCell[i] + 1;
        valueOfCellIds[i] =  valueOfCellIds[i] + 1;
        h0[i] =  h0[i] + 1;
        vU[i] =  vU[i] + 1;
        vV[i] =  vV[i] + 1;
        vUh[i] =  vUh[i] + 1;
        vVh[i] =  vVh[i] + 1;
    }
    for (int i = 0; i < numberOfCells; ++i) {
        vUh0[i] =  vUh0[i] + 1;
        vVh0[i] =  vVh0[i] + 1;
        ghh[i] =  ghh[i] + 1;
        sfx[i] =  sfx[i] + 1;
        sfy[i] =  sfy[i] + 1;
        qIn[i] =  qIn[i] + 1;
        for(int j = 0; j < nEdges; ++j) {
            neighborIds[i * nEdges + j] = neighborIds[i * nEdges + j] + 1;
        }
        for(int j = 0; j < nEdges; ++j) {
            typeInterface[i * nEdges + j] = typeInterface[i * nEdges + j] + 1;
        }
    }

}

สิ่งนี้แสดงให้เห็นในระดับที่สมเหตุสมผลว่าการพลาดแคชเป็นสาเหตุของการชะลอตัว สิ่งสำคัญคือต้องสังเกตว่าตัวแปรไม่ได้ขึ้นอยู่กับดังนั้นจึงสามารถสร้างโซลูชันแบบเธรดได้อย่างง่ายดาย

กู้คืนคำสั่งซื้อแล้ว

ตามความคิดเห็นของ stefans ฉันได้ลองจัดกลุ่มในโครงสร้างโดยใช้ขนาดดั้งเดิม สิ่งนี้จะลบแรงดันแคชทันทีในลักษณะเดียวกัน ผลลัพธ์คือเวอร์ชัน c ++ (CCFLAG -O3) เร็วกว่าเวอร์ชันจาวาประมาณ 15%

หารายได้ไม่สั้นหรือสวย

#include <vector>
#include <cmath>
#include <iostream>
 
 
 
class FloodIsolation {
    struct item{
      char floodedCells;
      char floodedCellsTimeInterval;
      double valueOfCellIds;
      double h;
      double h0;
      double vU;
      double vV;
      double vUh;
      double vVh;
      double vUh0;
      double vVh0;
      double sfx;
      double sfy;
      double qInflow;
      double qStartTime;
      double qEndTime;
      double qIn;
      double nx;
      double ny;
      double ghh;
      double floorLevels;
      int lowerFloorCells;
      char flagInterface;
      char floorCompletelyFilled;
      double cellLocationX;
      double cellLocationY;
      double cellLocationZ;
      int levelOfCell;
    };
    struct inner_item{
      int typeInterface;
      int neighborIds;
    };

    std::vector<inner_item> inner_data;
    std::vector<item> data;

public:
    FloodIsolation() :
            numberOfCells(20000), inner_data(numberOfCells * nEdges), data(numberOfCells)
   {

    }
    ~FloodIsolation(){
    }
 
    void isUpdateNeeded() {
        for (int i = 0; i < numberOfCells; ++i) {
            data[i].h = data[i].h + 1;
            data[i].floodedCells = !data[i].floodedCells;
            data[i].floodedCellsTimeInterval = !data[i].floodedCellsTimeInterval;
            data[i].qInflow = data[i].qInflow + 1;
            data[i].qStartTime = data[i].qStartTime + 1;
            data[i].qEndTime = data[i].qEndTime + 1;
            data[i].lowerFloorCells = data[i].lowerFloorCells + 1;
            data[i].cellLocationX = data[i].cellLocationX + 1;
            data[i].cellLocationY = data[i].cellLocationY + 1;
            data[i].cellLocationZ = data[i].cellLocationZ + 1;
            data[i].levelOfCell = data[i].levelOfCell + 1;
            data[i].valueOfCellIds = data[i].valueOfCellIds + 1;
            data[i].h0 = data[i].h0 + 1;
            data[i].vU = data[i].vU + 1;
            data[i].vV = data[i].vV + 1;
            data[i].vUh = data[i].vUh + 1;
            data[i].vVh = data[i].vVh + 1;
            data[i].vUh0 = data[i].vUh0 + 1;
            data[i].vVh0 = data[i].vVh0 + 1;
            data[i].ghh = data[i].ghh + 1;
            data[i].sfx = data[i].sfx + 1;
            data[i].sfy = data[i].sfy + 1;
            data[i].qIn = data[i].qIn + 1;
            for(int j = 0; j < nEdges; ++j) {
                inner_data[i * nEdges + j].neighborIds = inner_data[i * nEdges + j].neighborIds + 1;
                inner_data[i * nEdges + j].typeInterface = inner_data[i * nEdges + j].typeInterface + 1;
            }
        }
 
    }
 
    static const int nEdges;
private:
 
    const int numberOfCells;

};
 
const int FloodIsolation::nEdges = 6;

int main() {
    FloodIsolation isolation;
    clock_t start = clock();
    for (int i = 0; i < 4400; ++i) {
        if(i % 100 == 0) {
            std::cout << i << "\n";
        }
        isolation.isUpdateNeeded();
    }

    clock_t stop = clock();
    std::cout << "Time: " << difftime(stop, start) / 1000 << "\n";
}
                                                                              

ผลลัพธ์ของฉันแตกต่างจาก Jerry Coffins เล็กน้อยสำหรับขนาดดั้งเดิม สำหรับฉันความแตกต่างยังคงอยู่ อาจเป็นเวอร์ชัน java ของฉัน 1.7.0_75


12
อาจเป็นความคิดที่ดีที่จะจัดกลุ่มข้อมูลนั้นในโครงสร้างและมีเวกเตอร์เพียงตัวเดียว
stefan

ฉันใช้มือถือเลยทำการวัดไม่ได้ ;-) แต่เวกเตอร์อันเดียวน่าจะดี (ในแง่ของการจัดสรร)
stefan

1
ใช้++ความช่วยเหลือในด้านใดหรือไม่? x = x + 1ดูเหมือนชะมัด clunky ++xเมื่อเทียบกับ
tadman

3
โปรดแก้ไขคำที่สะกดผิด "ผลลัพธ์" มันกำลังฆ่าฉัน .. :)
FleetC0m

1
หากตัววนซ้ำทั้งหมดพอดีกับรีจิสเตอร์เดียวการทำสำเนาอาจเร็วกว่าการอัปเดตในบางกรณี หากคุณกำลังทำการอัปเดตนี่เป็นเพราะคุณมีแนวโน้มที่จะใช้ค่าที่อัปเดตในภายหลัง ดังนั้นคุณจึงมีการพึ่งพาการอ่านหลังเขียน หากคุณอัปเดต แต่ต้องการเพียงค่าเก่าการดำเนินการเหล่านั้นจะไม่ขึ้นอยู่กับกันและกันและ CPU มีพื้นที่มากขึ้นในการทำแบบขนานเช่นบนท่อที่แตกต่างกันทำให้ IPC มีประสิทธิภาพเพิ่มขึ้น
Piotr Kołaczkowski

20

ตามที่ @Stefan เดาในความคิดเห็นเกี่ยวกับคำตอบของ @ CaptainGiraffe คุณจะได้รับไม่น้อยโดยใช้เวกเตอร์ของโครงสร้างแทนโครงสร้างของเวกเตอร์ รหัสที่แก้ไขมีลักษณะดังนี้:

#include <vector>
#include <cmath>
#include <iostream>
#include <time.h>

class FloodIsolation {
public:
    FloodIsolation() :
            h(0),
            floodedCells(0),
            floodedCellsTimeInterval(0),
            qInflow(0),
            qStartTime(0),
            qEndTime(0),
            lowerFloorCells(0),
            cellLocationX(0),
            cellLocationY(0),
            cellLocationZ(0),
            levelOfCell(0),
            valueOfCellIds(0),
            h0(0),
            vU(0),
            vV(0),
            vUh(0),
            vVh(0),
            vUh0(0),
            vVh0(0),
            ghh(0),
            sfx(0),
            sfy(0),
            qIn(0),
            typeInterface(nEdges, 0),
            neighborIds(nEdges, 0)
    {
    }

    ~FloodIsolation(){
    }

    void Update() {
        h =  h + 1;
        floodedCells =  !floodedCells;
        floodedCellsTimeInterval =  !floodedCellsTimeInterval;
        qInflow =  qInflow + 1;
        qStartTime =  qStartTime + 1;
        qEndTime =  qEndTime + 1;
        lowerFloorCells =  lowerFloorCells + 1;
        cellLocationX =  cellLocationX + 1;
        cellLocationY =  cellLocationY + 1;
        cellLocationZ =  cellLocationZ + 1;
        levelOfCell =  levelOfCell + 1;
        valueOfCellIds =  valueOfCellIds + 1;
        h0 =  h0 + 1;
        vU =  vU + 1;
        vV =  vV + 1;
        vUh =  vUh + 1;
        vVh =  vVh + 1;
        vUh0 =  vUh0 + 1;
        vVh0 =  vVh0 + 1;
        ghh =  ghh + 1;
        sfx =  sfx + 1;
        sfy =  sfy + 1;
        qIn =  qIn + 1;
        for(int j = 0; j < nEdges; ++j) {
            ++typeInterface[j];
            ++neighborIds[j];
        }       
    }

private:

    static const int nEdges = 6;
    bool floodedCells;
    bool floodedCellsTimeInterval;

    std::vector<int> neighborIds;
    double valueOfCellIds;
    double h;
    double h0;
    double vU;
    double vV;
    double vUh;
    double vVh;
    double vUh0;
    double vVh0;
    double ghh;
    double sfx;
    double sfy;
    double qInflow;
    double qStartTime;
    double qEndTime;
    double qIn;
    double nx;
    double ny;
    double floorLevels;
    int lowerFloorCells;
    bool flagInterface;
    std::vector<int> typeInterface;
    bool floorCompleteleyFilled;
    double cellLocationX;
    double cellLocationY;
    double cellLocationZ;
    int levelOfCell;
};

int main() {
    std::vector<FloodIsolation> isolation(20000);
    clock_t start = clock();
    for (int i = 0; i < 400; ++i) {
        if(i % 100 == 0) {
            std::cout << i << "\n";
        }

        for (auto &f : isolation)
            f.Update();
    }
    clock_t stop = clock();
    std::cout << "Time: " << difftime(stop, start) / 1000 << "\n";
}

รวบรวมด้วยคอมไพเลอร์จาก VC ++ 2015 CTP โดยใช้-EHsc -O2b2 -GL -Qparฉันได้ผลลัพธ์ดังนี้:

0
100
200
300
Time: 0.135

การคอมไพล์ด้วย g ++ ให้ผลลัพธ์ที่ช้าลงเล็กน้อย:

0
100
200
300
Time: 0.156

บนฮาร์ดแวร์เดียวกันโดยใช้คอมไพเลอร์ / JVM จาก Java 8u45 ฉันได้ผลลัพธ์ดังนี้:

0
100
200
300
Time: 181

ซึ่งช้ากว่าเวอร์ชันจาก VC ++ ประมาณ 35% และช้ากว่าเวอร์ชันจาก g ++ ประมาณ 16%

หากเราเพิ่มจำนวนการทำซ้ำเป็น 2000 ที่ต้องการความแตกต่างจะลดลงเหลือเพียง 3% โดยชี้ให้เห็นว่าส่วนหนึ่งของข้อได้เปรียบของ C ++ ในกรณีนี้คือการโหลดที่เร็วขึ้น (ปัญหาที่เกิดกับ Java ตลอดกาล) ไม่ใช่ในการดำเนินการจริงๆ สิ่งนี้ไม่ได้ทำให้ฉันประหลาดใจในกรณีนี้ - การคำนวณที่วัดได้ (ในรหัสที่โพสต์) เป็นเรื่องเล็กน้อยมากจนฉันสงสัยว่าคอมไพเลอร์ส่วนใหญ่สามารถทำอะไรได้มากมายเพื่อเพิ่มประสิทธิภาพ


1
ยังมีช่องว่างสำหรับการปรับปรุงแม้ว่าสิ่งนี้จะไม่ส่งผลกระทบต่อประสิทธิภาพมากนัก: การจัดกลุ่มตัวแปรบูลีน (โดยทั่วไปจะจัดกลุ่มตัวแปรประเภทเดียวกัน)
stefan

1
@stefan: มี แต่ฉันตั้งใจที่จะหลีกเลี่ยงการเพิ่มประสิทธิภาพโค้ดอย่างหนักและแทนที่จะทำ (โดยประมาณ) ขั้นต่ำที่จำเป็นเพื่อลบปัญหาที่ชัดเจนที่สุดในการใช้งานดั้งเดิม ถ้าฉันต้องการเพิ่มประสิทธิภาพจริงๆฉันจะเพิ่ม a #pragma ompและ (อาจ) ทำงานเล็กน้อยเพื่อให้แน่ใจว่าการวนซ้ำแต่ละครั้งเป็นอิสระ นั่นจะใช้เวลาค่อนข้างน้อยในการรับ ~ Nx speedup โดยที่ N คือจำนวนแกนประมวลผลที่มีอยู่
Jerry Coffin

จุดดี. นี่ก็เพียงพอแล้วสำหรับคำตอบสำหรับคำถามนี้
stefan

181 หน่วยเวลา 35% ช้ากว่า 0.135 หน่วยเวลาอย่างไรและ 16% ช้ากว่า 0.156 หน่วยเวลาอย่างไร คุณหมายความว่าระยะเวลาของเวอร์ชัน Java คือ 0.181 หรือไม่?
jamesdlin

1
@jamesdlin: พวกเขาใช้หน่วยที่แตกต่างกัน (ปล่อยไว้อย่างนั้นเพราะมันเป็นสิ่งที่อยู่ในต้นฉบับ) รหัส C ++ ให้เวลาเป็นวินาที แต่รหัส Java ให้เวลาเป็นมิลลิวินาที
Jerry Coffin

9

ฉันสงสัยว่านี่เกี่ยวกับการจัดสรรหน่วยความจำ

ฉันคิดว่าจะJavaคว้าบล็อกที่อยู่ติดกันขนาดใหญ่เมื่อเริ่มต้นโปรแกรมในขณะที่C++ที่ระบบปฏิบัติการขอบิตและชิ้นส่วนตามที่ดำเนินการไป

ในการทดสอบทฤษฎีนั้นฉันได้ทำการปรับเปลี่ยนหนึ่งครั้งกับC++เวอร์ชันและมันก็เริ่มทำงานเร็วกว่าJavaเวอร์ชันเล็กน้อย:

int main() {
    {
        // grab a large chunk of contiguous memory and liberate it
        std::vector<double> alloc(20000 * 20);
    }
    FloodIsolation isolation;
    clock_t start = clock();
    for (int i = 0; i < 400; ++i) {
        if(i % 100 == 0) {
            std::cout << i << "\n";
        }
        isolation.isUpdateNeeded();
    }
    clock_t stop = clock();
    std::cout << "Time: " << (1000 * difftime(stop, start) / CLOCKS_PER_SEC) << "\n";
}

รันไทม์ที่ไม่มีเวกเตอร์การจัดสรรล่วงหน้า:

0
100
200
300
Time: 1250.31

รันไทม์ที่มีการจัดสรรเวกเตอร์ล่วงหน้า:

0
100
200
300
Time: 331.214

รันไทม์สำหรับJavaเวอร์ชัน:

0
100
200
300
Time: 407

คุณไม่สามารถพึ่งพาสิ่งนั้นได้จริงๆ ข้อมูลในFloodIsolationอาจยังคงถูกจัดสรรที่อื่น
stefan

@stefan ยังคงเป็นผลลัพธ์ที่น่าสนใจ
กัปตันยีราฟ

@CaptainGiraffe เป็นฉันไม่ได้บอกว่ามันไร้ประโยชน์ ;-)
stefan

2
@stefan ฉันไม่ได้เสนอให้เป็นวิธีแก้ปัญหาเพียงแค่ตรวจสอบสิ่งที่ฉันคิดว่าเป็นปัญหา ดูเหมือนว่าอาจไม่มีส่วนเกี่ยวข้องกับการแคช แต่ C ++ RTS แตกต่างจาก Java อย่างไร
Galik

1
@Galik ไม่ใช่สาเหตุเสมอไปแม้ว่าจะค่อนข้างน่าสนใจที่เห็นว่ามันมีผลกระทบอย่างมากต่อแพลตฟอร์มของคุณ ใน ideone ฉันไม่สามารถสร้างผลลัพธ์ของคุณได้ (ดูเหมือนว่าบล็อกที่จัดสรรจะไม่ถูกนำมาใช้ซ้ำ): ideone.com/im4NMOอย่างไรก็ตามเวกเตอร์ของโซลูชันโครงสร้างมีผลกระทบต่อประสิทธิภาพที่สอดคล้องกันมากขึ้น: ideone.com/b0VWSN
stefan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.