为什么Java的执行速度似乎比C++;-第二部分 介绍
这是我之前问的问题的后续问题:。通过这篇文章,我学到了一些重要的东西: <> Li >我没有使用Ctrl +F5编译和运行VisualStudioC++快照上的C++代码,这导致调试速度减慢代码执行。为什么Java的执行速度似乎比C++;-第二部分 介绍,java,c++,visual-studio-2010,netbeans7.0,Java,C++,Visual Studio 2010,Netbeans7.0,这是我之前问的问题的后续问题:。通过这篇文章,我学到了一些重要的东西: Li >我没有使用Ctrl +F5编译和运行VisualStudioC++快照上的C++代码,这导致调试速度减慢代码执行。 向量在处理数据数组方面与指针一样好(如果不是更好的话) 我的C++很糟糕。^ ^ 更好的执行时间测试是迭代,而不是递归 我试图编写一个更简单的程序,它不使用指针(或Java等价物中的数组),并且执行起来非常简单。即使这样,java执行速度也比C++执行快。我做错了什么 代码: 爪哇: 更新2: 我用
我用新的回合函数改变C++代码,我更新了执行时间。 更新3: 多亏了史蒂夫·汤森和洛杜维克,我找到了问题的答案。在编译我的代码到程序集并对其进行评估之后,我发现C++程序集比java程序集创建更多的内存动作。这是因为我的JDK使用的是X64编译器,而我的VisualStudioExpress C++不能使用X64架构,因此本质上是较慢的。因此,我安装了WindowsSDK7.1,并使用这些编译器编译我的代码(在发行版中,使用ctrl+F5)。目前,时间比率为:
C++:~2.2秒 Java:~4.6秒<>现在我可以编译C++中的所有代码,最终得到我的算法所需的速度。p> 这是因为打印了值。与实际循环无关。您肯定不想对输出计时。删除每个循环中的输出语句并重新运行,以便更好地比较您真正感兴趣的内容。否则,您还需要对输出功能和视频驱动程序进行基准测试。产生的速度实际上可能取决于您运行的控制台窗口在测试时是否被遮挡或最小化
确保C++中没有运行调试生成。这将比发布慢得多,与启动流程的方式无关
编辑:我在本地复制了这个测试场景,无法得到相同的结果。修改代码(如下)以删除输出后,Java需要5.40754388秒public static void main(String args[]) { // Number of iterations
double iterations = 1E8;
double temp; // Create the variables for timing
double start;
int matches = 0;
double end;
double duration;
// end - start //Run performance test
System.out.println("Start");
start = System.nanoTime();
for (double i = 0; i < iterations; i += 1) {
// Overhead and display
temp = Math.log10(i);
if (Math.round(temp) == temp) {
++matches;
}
}
end = System.nanoTime();
System.out.println("End");
// Output performance test results
duration = (end - start) / 1E9;
System.out.println("Duration: " + duration);
}
publicstaticvoidmain(字符串args[]){//迭代次数
双迭代=1E8;
double temp;//创建用于计时的变量
双启动;
int匹配=0;
双端;
双倍持续时间;
//结束-开始//运行性能测试
系统输出打印项次(“开始”);
start=System.nanoTime();
对于(双i=0;i
下面的C++代码需要5062毫秒。这是Windows上的JDK 6u21和VC++10 Express的代码
unsigned int count(1E8);
DWORD end;
DWORD start(::GetTickCount());
double next = 0.0;
int matches(0);
for (int i = 0; i < count; ++i)
{
double temp = log10(double(i));
if (temp == floor(temp + 0.5))
{
++count;
}
}
end = ::GetTickCount();
std::cout << end - start << "ms for " << 100000000 << " log10s" << std::endl;
无符号整数计数(1E8);
德沃德端;
DWORD start(::GetTickCount());
下一步加倍=0.0;
int匹配(0);
对于(int i=0;i STD::CUT> P>这是一个安全的假设,任何时候你看到java都优于C++,尤其是在这么大的范围内,你做了一些错事。因为这是第二个关于这种微观优化的问题,我觉得我应该建议找一个不那么无用的爱好
<>这回答了你的问题:你使用C++(实际上,你的操作系统)是错误的。至于隐含的问题(如何?),很简单:endl
刷新流,Java继续对其进行缓冲。将cout
行替换为:
cout << temp << "\n";
<代码> cOUT 如@ Mat注释,您的C++ <代码>圆< /C> >与javas<代码>数学不一样。表示Math.round
与(长)Math.floor(a+0.5d)
是相同的
注意,在C++中,不向长转换将更快(也可能在java中)。
可能想查看< /P>
<> P>可能有一大堆因素可以解释为什么java代码运行得比C++代码快。其中一个因素可能是,对于这个测试用例,Java代码更快。我甚至不认为这是一种语言比另一种语言快的声明。
如果我要对您的工作方式做一个更改,我会使用time
命令将代码移植到linux和time runtime。恭喜,你刚刚删除了整个Windows .h文件。< p>只是总结了其他人在这里所说的:C++ iSoFrand功能与java中的不同。在C++输出中,IOFFROW在输出每个字符之前创建一个称为哨兵的内部类型。例如,ostream::sentry使用RAII习惯用法来确保流处于一致状态。在多线程环境(在许多情况下是默认环境)中,在打印每个字符以避免竞争条件后,sentry还用于锁定互斥对象并将其解锁。互斥锁/解锁操作非常昂贵,这就是您面临这种减速的原因
Java转向另一个方向,对整个输出字符串只锁定/解锁互斥锁一次。这就是为什么如果您要从多个线程输出到cout,您会看到非常混乱的输出,但所有字符都会在那里
<> P>如果您直接使用流缓冲区,只刷新输出,就可以使C++流性能。为了测试这种行为,只需关闭测试的线程支持,C++的可执行文件就应该运行得更快。
我解放军
public static void main(String args[]) { // Number of iterations
double iterations = 1E8;
double temp; // Create the variables for timing
double start;
int matches = 0;
double end;
double duration;
// end - start //Run performance test
System.out.println("Start");
start = System.nanoTime();
for (double i = 0; i < iterations; i += 1) {
// Overhead and display
temp = Math.log10(i);
if (Math.round(temp) == temp) {
++matches;
}
}
end = System.nanoTime();
System.out.println("End");
// Output performance test results
duration = (end - start) / 1E9;
System.out.println("Duration: " + duration);
}
unsigned int count(1E8);
DWORD end;
DWORD start(::GetTickCount());
double next = 0.0;
int matches(0);
for (int i = 0; i < count; ++i)
{
double temp = log10(double(i));
if (temp == floor(temp + 0.5))
{
++count;
}
}
end = ::GetTickCount();
std::cout << end - start << "ms for " << 100000000 << " log10s" << std::endl;
cout << temp << "\n";
cout << "test" << '\n';
_Myt& __CLR_OR_THIS_CALL operator<<(double _Val)
{// insert a double
ios_base::iostate _State = ios_base::goodbit;
const sentry _Ok(*this);
...
}
template<class _Elem, class _Traits>
class basic_ostream
{
class _Sentry_base
{
///...
__CLR_OR_THIS_CALL _Sentry_base(_Myt& _Ostr)
: _Myostr(_Ostr)
{ // lock the stream buffer, if there
if (_Myostr.rdbuf() != 0)
_Myostr.rdbuf()->_Lock();
}
///...
};
};
template<class _Elem, class _Traits>
void basic_streambuf::_Lock()
{ // set the thread lock
_Mylock._Lock();
}
void __thiscall _Mutex::_Lock()
{ // lock mutex
_Mtxlock((_Rmtx*)_Mtx);
}
void __CLRCALL_PURE_OR_CDECL _Mtxlock(_Rmtx *_Mtx)
{ /* lock mutex */
// some additional stuff which is not called...
EnterCriticalSection(_Mtx);
}
Multithreaded DLL/Release build:
Start
-1.#INF
0
1
2
3
4
5
6
7
End
Duration: 4.43151
Press any key to continue . . .
Multithreaded DLL/Release with '\n' instead of endl
Start
-1.#INF
0
1
2
3
4
5
6
7
End
Duration: 4.13076
Press any key to continue . . .
inline bool output_double(double const& val)
{
typedef num_put<char> facet;
facet const& nput_facet = use_facet<facet>(cout.getloc());
if(!nput_facet.put(facet::iter_type(cout.rdbuf()), cout, cout.fill(), val).failed())
return cout.rdbuf()->sputc('\n')!='\n';
return false;
}
Multithreaded DLL/Release without locks by directly writing to streambuf
Start
-1.#INF
0
1
2
3
4
5
6
7
End
Duration: 4.00943
Press any key to continue . . .
size_t iterations = 100000000; //=1E8
...
//Run performance test
size_t i;
cout << "Start" << endl;
QueryPerformanceCounter(&start);
for(i=0; i<iterations; ++i)
{
//Overhead and display
temp = log10(double(i));
if(round(temp) == temp)
output_double(temp);
}
QueryPerformanceCounter(&end);
cout << "End" << endl;
...
Start
-1.#INF
0
1
2
3
4
5
6
7
End
Duration: 3.69653
Press any key to continue . . .
sehe@natty:/tmp$ time java PerformanceTest2
real 0m5.246s
user 0m5.250s
sys 0m0.000s
sehe@natty:/tmp$ time ./t
real 0m5.656s
user 0m5.650s
sys 0m0.000s
all: PerformanceTest2 t
PerformanceTest2: PerformanceTest2.java
javac $<
t: t.cpp
g++ -g -O2 -ffast-math -march=native $< -o $@
#include <stdio.h>
#include <cmath>
inline double round(double value)
{
return floor(0.5 + value);
}
int main()
{
//Number of iterations
double iterations = 1E8;
double temp;
//Run performance test
for(double i = 0; i < iterations; i += 1)
{
//Overhead and display
temp = log10(i);
if(round(temp) == temp)
{
printf("%F\n", temp);
}
}
return 0;
}
public class PerformanceTest2
{
public static void main(String args[])
{
//Number of iterations
double iterations = 1E8;
double temp;
//Run performance test
for(double i = 0; i < iterations; i += 1)
{
//Overhead and display
temp = Math.log10(i);
if(Math.round(temp) == temp)
{
System.out.println(temp);
}
}
}
}