语言的速度
這些年我的日常開發(fā)總是在使用C/C++(gcc和vc都用)和匯編,還用過(guò)其他各類腳本系統(tǒng)做小的應(yīng)用,asp、php和jsp的網(wǎng)站也偶爾做接手做做,前幾年用C#做過(guò)很簡(jiǎn)單的串口監(jiān)控小程序,當(dāng)時(shí)感覺(jué)還是很好的,去年以來(lái)開始做仿真系統(tǒng)就用C#,那種慢已經(jīng)不是自己可以容忍的了,有時(shí)候真的有早年間用486編譯linux核心的那種感覺(jué)——等吧,喝點(diǎn)水去個(gè)廁所就會(huì)好。基于java的編程早年間做過(guò),主要閑慢,使用了jit技術(shù)后,C#和java的速度其實(shí)都有非常高的提升,可是在真正運(yùn)行到實(shí)際系統(tǒng)時(shí)候總是感覺(jué)有點(diǎn)卡,像ios和android,600M的iphone跑同一款游戲就是比1G的android要快。很多人說(shuō)是框架問(wèn)題,說(shuō)蘋果的優(yōu)化,其實(shí)就是語(yǔ)言本身的問(wèn)題,如果都是運(yùn)行一個(gè)十幾億次的循環(huán)加法,使用jit技術(shù)的java和C#不會(huì)比C或者C++差,可是在無(wú)數(shù)的語(yǔ)言對(duì)象的調(diào)用消除下,系統(tǒng)的差異被一點(diǎn)點(diǎn)放大,卡、鈍就成了此類系統(tǒng)的特征,現(xiàn)在的android機(jī)器已經(jīng)向2GHz、8核心直奔而去,也許這就是那個(gè)瓶頸了。
我們可以說(shuō)C#和java是偉大的語(yǔ)言,在我的工作領(lǐng)域,沒(méi)有什么跨平臺(tái)的開發(fā),都是C/C++/匯編,java的跨平臺(tái)性我就體會(huì)不到了。如果說(shuō)他們的偉大是因?yàn)橛袩o(wú)窮的庫(kù),我倒是要承認(rèn),java和C#的下的框架層出不窮,C++的boost整了多少年才一點(diǎn)點(diǎn)變成標(biāo)準(zhǔn)。我記得09年我做了一個(gè)用正則表達(dá)式的軟件,那還是因?yàn)関s2008集成的緣故,可是正則表達(dá)式早就在C#和java里面集成使用了,當(dāng)然alt里面的正則可以忽略,那個(gè)真的不好用。如果不是boost有已經(jīng)變異好的版本,我都懶得用。但是只要用過(guò)boost的,對(duì)java和C#也就淡然了。
我始終認(rèn)為并不是C或者C++不好,而是大家為了自己的利益而畫地為牢,看看C++和C的發(fā)展路線吧,簡(jiǎn)直就是蝸牛的速度,現(xiàn)在可好,找C#程序員一堆一堆的,C程序員倒是都是,可是沒(méi)有幾個(gè)好的。看看國(guó)外程序員用vi去做vc的程序,我們簡(jiǎn)直應(yīng)該汗顏了。
最后我要說(shuō)明,我并不是對(duì)java或者C#有偏見,這兩個(gè)語(yǔ)言我都做過(guò)軟件,我只是認(rèn)為:語(yǔ)言只是一種工具,在合適的領(lǐng)域使用合適的語(yǔ)言才是一個(gè)程序員最合適的選擇。
http://chipset04180.blog.163.com/blog/static/27693238200810264270796/
Why Java Will Always Be Slower than C++???
2008-11-26 16:27:00|??分類:?隨意|字號(hào)?訂閱
by Dejan Jelovic
?
"Java is high performance. By high performance we mean adequate. By adequate we mean slow."?-?Mr. Bunny
?
Anybody that has ever used a non-trivial Java program or has programmed in Java knows that Java is slower than native programs written in C++. This is a fact of life, something that we accept when we use Java.
However, many folks would like to convince us that this is just a temporary condition. Java is not slow by design, they say. Instead, it is slow because today's JIT implementations are relatively young and don't do all the optimizations they could.
This is incorrect. No matter how good the JITs get, Java will?always?be slower than C++.
The Idea
People who claim that Java can be as fast as C++ or even faster often base their opinion on the idea that more disciplined languages give the compiler more room for optimization. So, unless you are going to hand-optimize the whole program, the compiler will do a better job overall.
This is true. Fortran still kicks C++'s ass in numeric computing because it is more disciplined. With no fear of pointer aliasing the compiler can optimize better. The only way that C++ can rival the speed of Fortran is with a cleverly designed active library like?Blitz++.
However, in order to achieve overall results like that, the language must be designed to give the compiler?room for optimization.?Unfortunately, Java was not designed that way. So no matter how smart the compilers get, Java will never approach the speed of C++.
The Benchmarks
Perversely, the only area in which Java can be as fast as C++ is a typical benchmark. If you need to calculate Nth Fibonacci number or run Linpack, there is no reason why Java cannot be as fast as C++. As long as all the computation stays in one class and uses only primitive data types like int and double, the Java compiler is on equal footing with the C++ compiler.
The Real World
The moment you start using objects in your program, Java looses the potential for optimization. This section lists some of the reasons why.
1. All Objects are Allocated on the Heap
Java only allocates primitive data types like int and double and object references on the stack. All objects are allocated on the heap.
For large objects which usually have identity semantics, this is not a handicap. C++ programmers will also allocate these objects on the heap. However, for small objects with value semantics, this is a major performance killer.
What small objects? For me these are iterators. I use a lot of them in my designs. Someone else may use complex numbers. A 3D programmer may use a vector or a point class. People dealing with time series data will use a time class. Anybody using these will definitely hate trading a zero-time stack allocation for a constant-time heap allocation. Put that in a loop and that becomes O (n) vs. zero. Add another loop and you get O (n^2) vs. again, zero.
2. Lots of Casts
With the advent of templates, good C++ programmers have been able to avoid casts almost completely in high-level programs. Unfortunately, Java doesn't have templates, so Java code is typically full of casts.
What does that mean for performance? Well, all casts in Java are dynamic casts, which are expensive. How expensive? Consider how you would implement a dynamic cast:
The fastest thing you could do is assign a number to each class and then have a matrix that tells if any two classes are related, and if they are, what is the offset that needs to be added to the pointer in order to make the cast. In that case, the pseudo-code for the cast would look something like this:
DestinationClass makeCast (Object o, Class destinationClass) {Class sourceClass = o.getClass (); // JIT compile-timeint sourceClassId = sourceClass.getId (); // JIT compile-timeint destinationId = destinationClass.getId ();int offset = ourTable [sourceClassId][destinationClassId];if (offset != ILLEGAL_OFFSET_VALUE) {return <object o adjusted for offset>;}else {throw new IllegalCastException ();} }Quite a lot of code, this little cast! And this here is a rosy picture - using a matrix to represent class relationships takes up a lot of memory and no sane compiler out there would do that. Instead, they will either use a map or walk the inheritance hierarchy - both of which will slow things down even further.
3. Increased Memory Use
Java programs use about double the memory of comparable C++ programs to store the data. There are three reasons for this:
A larger memory footprint increases the probability that parts of the program will be swapped out to the disk. And swap file usage kills the speed like nothing else.
4. Lack of Control over Details
Java was intentionally designed to be a simple language. Many of the features available in C++ that give the programmer control over details were intentionally stripped away.
For example, in C++ one can implement schemes that improve the locality of reference. Or allocate and free many objects at once. Or play pointer tricks to make member access faster. Etc.
None of these schemes are available in Java.
5. No High-Level Optimizations
Programmers deal with high-level concepts. Unlike them, compilers deal exclusively with low-level ones. To a programmer, a class named Matrix represents a different high-level concept from a class named Vector. To a compiler, those names are only entries in the symbol table. What it cares about are the functions that those classes contain, and the statements inside those functions.
Now think about this: say you implement the function?exp (double x, double y)?that raises?x?to the exponent?y.?Can a compiler, just by looking at the statements in that function, figure out that?exp (exp (x, 2), 0.5)?can be optimized by simply replacing it with?x? Of course not!
All the optimizations that a compiler can do are done at the statement level, and they are built into the compiler. So although the programmer might know that two functions are symmetric and cancel each other now, or that the order of some function calls is irrelevant in some place, unless the compiler can figure it out by looking at the statements, the optimization will not be done.
So, if a high-level optimization is to be done, there has to be a way for the programmer to specify the high-level optimization rules for the compiler.
No popular programming language/system does this today. At least not in the totally open sense, like what the?Microsoft's Intentional Programming?project promises. However, in C++ you can do?template metaprogramming?to implement optimizations that deal with high-level objects. Temporary elimination, partial evaluation, symmetric function call removal and other optimizations can be implemented using templates. Of course, not all high-level optimizations can be done this way. And implementing some of these things can be cumbersome. But a lot can be done, and people have implemented some?snazzy libraries?using these techniques.
Unfortunately, Java doesn't have any metaprogramming facilities, and thus high-level optimizations are not possible in Java.
So...
Java, with the current language features, will never be as fast as C++. This pretty much means that it's not a sensible choice for high-performance software and the highly competitive COTS arena. But its small learning curve, its forgiveness, and its large standard library make it a good? choice for some small and medium-sized in-house and custom-built software.
?
?
Notes
1.? James Gosling?has proposed a number of language features that would help improve Java performance. You can find the text? here. Unfortunately, the Java language has not changed for four years, so it doesn't seem like these will be implemented any time soon.2.?The most promising effort to bring generic types to Java is?Generic Java. Unfortunately, GJ works by removing all type information when it compiles the program, so what the execution environment sees is the end is again the slow casts.
3.?The?Garbage Collection FAQ?contains the information that garbage collections?is?slower than customized allocator (point 4 in the above text).
4.?There is a paper that claims that?Garbage Collection Can Be Faster than Stack Allocation. But the requirement is that there is seven times more physical memory than what the program actually uses. Plus, it describes a stop-and-copy collector and doesn't take concurrency into account. [Peter Drayton:?FWIW, this is an over-simplification of the paper, which provides a means of calculating what the cross-over point is, but doesn't claim that 7 is a universal cross-over point: it is merely the crossover point he derives using the sample inputs in the paper.]
?
?
Feedback
I received a lot of feedback about this article. Here are the typical comments, together with my answers:
"You forgot to mention that all methods in Java are virtual, because nobody is using the final keyword."
The fact that people are not using the final keyword is not a problem with the language, but with the programmers using it. Also, virtual functions calls in general are not problematic because of the call overhead, but because of lost optimization opportunities. But since JITs know how to inline across virtual function boundaries, this is not a big deal.
Java can be faster than C++ because JITs can inline over virtual function boundaries.
C++ can also be compiled using JITs. Check out the C++ compiler in .NET.
In the end, speed doesn't matter. Computers spend most of their time waiting on our input.
Speed still maters. I still wait for my laptop to boot up. I wait for my compiler. I wait on Word when I have a long document.
I work in the financial markets industry. Sometimes I have to run a simulation over a huge data set. Speed matters in those cases.
It is possible for a JIT to allocate some objects on a stack.
Sure. Some.
Your casting pseudo-code is naive. For classes a check can be made based on inheritance depth.
First, that's only a tad faster than the matrix lookup.
Second, that works only for classes, which make up what percentage of casts? Low-level details are usually implemented through interfaces.
So we should all use assembly, ha!?
No. We should all use languages that make sense for a given project. Java is great because it has a large standard library that makes many common tasks easy. It's more portable than any other popular language (but not 100% portable - different platforms fire events at different times and in different order). It has garbage collection that makes memory management simpler and some constructs like closures possible.
But, at the same time, Java, just like any other language, has some deficiencies. It has no support for types with value semantics. Its synchronization constructs are not efficient enough. Its standard library relies on checked exceptions which are evil because they push implementation details into interfaces. Its performance could be better. The math library has some annoying problems. Etc.
Are these deficiencies a big deal? It depends on what you are building. So know a few languages and pick the one that, together with the compiler and available libraries, makes sense for a given project.
Trace back: http://www.jelovic.com/articles/why_java_is_slow.htm耍過(guò)Java程序,或者用Java碼過(guò)程序的人都曉得,Java要比用C++寫成的原生程序要慢。這是咱用Java時(shí)已經(jīng)承認(rèn)的事實(shí)。
不過(guò),很多人想要說(shuō)服我們說(shuō)這只不過(guò)是暫時(shí)的,他們說(shuō)Java從設(shè)計(jì)上來(lái)講并不慢,相反,只是現(xiàn)在的JIT實(shí)現(xiàn)相對(duì)比較嫩,有很多能優(yōu)化的地方JIT并沒(méi)有優(yōu)化到,拖了后腿。其實(shí)不然,不管JIT們多牛,Java永遠(yuǎn)要比C++慢。
我想說(shuō)...
宣揚(yáng)Java不慢于C++的人往往是覺(jué)得,(語(yǔ)法)嚴(yán)格的語(yǔ)言,可以讓編譯有更大的優(yōu)化空間。因此,除非你想做人肉編譯器優(yōu)化整個(gè)程序,否則通常都是編譯器做得更好。
這是真的。在數(shù)值計(jì)算領(lǐng)域,Fortran仍然勝于C++,的確因?yàn)樗鼑?yán)格。不用擔(dān)心指針瞎攪和,編譯器可以更安心地優(yōu)化。C++想打敗Fortran的唯一辦法,就是好好設(shè)計(jì)一個(gè)像Blitz++那樣的庫(kù)。
測(cè)試...
Java可以跟得上C++的地方,就是基準(zhǔn)測(cè)試。計(jì)算起第N個(gè)斐波納契數(shù),或者運(yùn)行起Linpack,Java沒(méi)理由不跟C++跑得一樣快。當(dāng)所有的計(jì) 算都放在一個(gè)類里,并且只使用基本的數(shù)據(jù)類型,比如說(shuō)int或者double時(shí),Java編譯器的確能跟得上C++的腳步。
事實(shí)...
當(dāng)開始在程序中使用對(duì)象的時(shí)候,Java就放松了潛在的優(yōu)化。這一節(jié)會(huì)告訴你為什么。
1.?所有的對(duì)象都是從堆里分配的。
Java從棧里分配的,就只有基本數(shù)據(jù)類型,如int,或者double,還有對(duì)象的引用。所有的對(duì)象都是從堆里分配的。
當(dāng)有大量語(yǔ)義上是一回事的對(duì)象時(shí),這不成問(wèn)題。C++同樣也是從堆上分配這些對(duì)象。但是,當(dāng)有值語(yǔ)義不同的小對(duì)象時(shí),這就是一個(gè)主要的性能殺手。
什么是小對(duì)象?對(duì)我來(lái)說(shuō),就是迭代器們。在設(shè)計(jì)中,我用了很多迭代器。別人可能會(huì)用復(fù)數(shù)。3D程序員可能會(huì)矢量或者點(diǎn)類。處理時(shí)間序列的人可能會(huì)有時(shí)間 類。使用這些類的人,無(wú)一例外地討厭把不費(fèi)時(shí)間的棧上分配換成花費(fèi)固定時(shí)間的堆上分配。假如把它放在一個(gè)循環(huán)里,就變成了O(n)對(duì)0了。如果再加一層循 環(huán),沒(méi)錯(cuò),又變成O(n^2)對(duì)0了。
2.?大量的轉(zhuǎn)換。
得益于模板,好的C++程序員甚至可以寫于完全沒(méi)有轉(zhuǎn)換的牛程序。不幸,Java沒(méi)有模板,所以Java代碼總是充滿了轉(zhuǎn)換。
對(duì)于性能,它們意味著什么?呃,在Java里所有的轉(zhuǎn)換都是很費(fèi)時(shí)的動(dòng)態(tài)轉(zhuǎn)換。多費(fèi)時(shí)?想想你可能會(huì)怎么樣實(shí)現(xiàn)轉(zhuǎn)換的:
最快的方法就是,給每一個(gè)類賦值一個(gè)序號(hào),然后用一個(gè)矩陣來(lái)描述任意兩個(gè)類是否相關(guān)的。如果是的話,需要給指針加上多少的位移才能進(jìn)行轉(zhuǎn)換。這種方法的偽碼看起來(lái)應(yīng)該是這樣的:
DestinationClass?makeCast?(Object?o,?Class?destinationClass)?{
????Class?sourceClass?=?o.getClass?();?//?JIT?compile-time
????int?sourceClassId?=?sourceClass.getId?();?//?JIT?compile-time
????int?destinationId?=?destinationClass.getId?();
????int?offset?=?ourTable?[sourceClassId][destinationClassId];
????if?(offset?!=?ILLEGAL_OFFSET_VALUE)?{
????????return?<object?o?adjusted?for?offset>;
????}
????else?{
????????throw?new?IllegalCastException?();
????}
}
好一堆代碼。這只是一個(gè)簡(jiǎn)單的情景——用矩陣來(lái)表示類的關(guān)系浪費(fèi)了一部分內(nèi)存,沒(méi)有哪個(gè)成熟的編譯器會(huì)這樣子做。他們會(huì)使用map或者遍歷繼承樹,這樣會(huì)變得更慢。
3.?攀升的內(nèi)存占用。
Java程序儲(chǔ)存數(shù)據(jù)占用的內(nèi)存大概是相當(dāng)?shù)腃++程序的兩倍。原因如下:
1.?啟用了垃圾收集的程序一般都比不使用垃圾收集的程序多花50%的內(nèi)存。
2.?本來(lái)C++里在棧上分配的對(duì)象,到了Java就在堆上分配了。
3.?Java對(duì)象比較大,因?yàn)樗械膶?duì)象都有一個(gè)虛表,還要加上對(duì)(線程)同步的原生支持。
大的內(nèi)存映像讓程序更大概率被放到磁盤的交換區(qū)去。沒(méi)有什么比交換文件更慢的了。
4.?缺少更細(xì)致的控制。
Java原來(lái)就是作為一種簡(jiǎn)單的語(yǔ)言來(lái)設(shè)計(jì)的。很多在C++里讓程序員控制細(xì)節(jié)的特性在Java里都被一腳踢開了。
比如說(shuō),在C++里可以改進(jìn)引用的位置(?)。或者一次申請(qǐng)和釋放很多個(gè)對(duì)象。或者用指針?biāo)R恍┬〖记?#xff0c;更快地訪問(wèn)成員。
5.?沒(méi)有高層次的優(yōu)化。
程序員處理高層次的概念。而編譯器處理剩下的低層次概念。對(duì)于程序員來(lái)說(shuō),一個(gè)叫Matrix的類就代表了比一個(gè)叫Vector的類更高層次的概念。而對(duì)于編譯器來(lái)說(shuō),這些名字都是符號(hào)表的一個(gè)入口。他們只關(guān)心類里面有哪些函數(shù),函數(shù)里面有哪些語(yǔ)句。
這樣想一下,比如說(shuō)要實(shí)現(xiàn)一個(gè)exp(double?x,?double?y)函數(shù),計(jì)算出x的y次冪。對(duì)于一個(gè)編譯器,它能只看一下這個(gè)函數(shù),然后指出,exp(exp(x,?2),?0.5)可以優(yōu)化成x自己?jiǎn)?#xff1f;當(dāng)然不行。
編譯器能做的優(yōu)化只是語(yǔ)句層面的,而y是在編譯器里面的。即使程序員知道兩個(gè)函數(shù)是對(duì)稱的,可以把它們都消去,或者函數(shù)的調(diào)用順序只是相反的,除非編譯器能只瞄一下語(yǔ)句,然后指出來(lái),不然優(yōu)化是不可能完成的。
所以,如果想要完成一個(gè)高水平的優(yōu)化,必須存在某種方法,可以讓程序員來(lái)告訴編譯器優(yōu)化的規(guī)則。
沒(méi)有哪個(gè)流行的程序語(yǔ)言/系統(tǒng)可以做到這點(diǎn),至少已知的方法,比如微軟承諾的智能語(yǔ)言,都不能。即便如此,在C++里可以用模板元編程來(lái)實(shí)現(xiàn)對(duì)高層次對(duì) 象的優(yōu)化。臨時(shí)消除,部分求值,對(duì)稱函數(shù)調(diào)用的消去,和其它可以用模板實(shí)現(xiàn)的優(yōu)化。當(dāng)然,不是所有的高層次優(yōu)化都可以這樣做。并且實(shí)現(xiàn)這些東西相當(dāng)麻煩。 但是大多數(shù)都可以完成,有人已經(jīng)用這些技術(shù)實(shí)現(xiàn)了好些時(shí)髦的庫(kù)。
不幸的是,Java沒(méi)有任何元編程的特質(zhì),因此在Java中不會(huì)有這種高層次的優(yōu)化。
所以...
由于存在這種語(yǔ)言特性,Java不可能達(dá)到C++這種速度。這相當(dāng)程序上暗示了,對(duì)于要求高性能的軟件和競(jìng)爭(zhēng)激烈的COTS舞臺(tái)上,使用Java不是一種明智的選擇。但是因?yàn)樗途彽膶W(xué)習(xí)曲線,它的容錯(cuò),和它龐大的標(biāo)準(zhǔn)庫(kù),所以適合開發(fā)中小型自用和定制軟件。
附記...
1.?有人向James?Gosling(誰(shuí)?google之...)提交了很多可以改進(jìn)Java性能的語(yǔ)言特性。文本在這里。不幸的是,Java語(yǔ)言已經(jīng)有四年沒(méi)有改動(dòng)過(guò)了,所以看起來(lái)這些提議似乎不會(huì)在一夜之間被實(shí)現(xiàn)。
2.?最有可能往Java里加入泛型的是Generic?Java。又很不幸的是,GJ只是通過(guò)在編譯時(shí)把所有類型信息去掉來(lái)支持泛型。所以最后面執(zhí)行環(huán)境看到的,仍然是緩慢的轉(zhuǎn)換。
3.?垃圾收集的FAQ包含了關(guān)于垃圾收集慢于定制分配器的信息(上面第四點(diǎn))。
4.?這里是一篇宣稱垃圾收集比棧分配的快的文章。但是它的要求是物理內(nèi)存必須是程序?qū)嶋H需要的內(nèi)存的七倍之多。還有,它描述的是一種stop- and-copy(是不是那種執(zhí)行到一半,然后停下來(lái),把內(nèi)存拷到另外一塊內(nèi)存,同時(shí)清除垃圾的那種方法?),而且還不是并發(fā)的。
反饋...
我收到很多關(guān)于這篇文章的反饋。附上一些典型的評(píng)論,還有我的回答:
“你還忘記了指出在Java里所有的方法都是虛方法,因?yàn)闆](méi)有人會(huì)加上final關(guān)鍵字。”
事實(shí)上,不使用final關(guān)鍵字不是問(wèn)題的關(guān)鍵所在,使用者才是。同時(shí),虛函數(shù)也沒(méi)有問(wèn)題,但是卻失去了優(yōu)化機(jī)會(huì)。自從JIT們知道怎么樣內(nèi)聯(lián)虛函數(shù),這就變得不那么顯著了。
JIT可以內(nèi)聯(lián)虛函數(shù),所以Java可以比C++更快。
C++也可以使用JIT編譯。不信的可以看看.NET的C++編譯器。
到最后的時(shí)候,速度并不重要。電腦浪費(fèi)了大部份時(shí)間在等待用戶輸入。
速度仍然很重要。我仍然在等我的筆記本啟動(dòng)起來(lái),我在等我的編譯器停下來(lái),我還要等Word打開一個(gè)超長(zhǎng)的文檔。
我在一個(gè)金融公司工作。有時(shí)候我必須對(duì)一個(gè)很大的數(shù)據(jù)集進(jìn)行模擬。速度在這種情況下都很重要。
有些JIT可以在棧上分配一些對(duì)象。
當(dāng)然,一些。
你的轉(zhuǎn)換代碼看起來(lái)很丑。可以在類的繼承層次上檢查類。
首先,這樣只比矩陣查找快一點(diǎn)點(diǎn)而已。
第二,這樣只能查找類,類只占多少?低層次的細(xì)節(jié)往往是通過(guò)接口來(lái)實(shí)現(xiàn)的。
哈,那么我們都應(yīng)該使用匯編?
不是的,我們都要使用對(duì)業(yè)務(wù)有用的語(yǔ)言。Java提供了龐大的標(biāo)準(zhǔn)庫(kù),讓很多任務(wù)變得容易,因此Java是偉大的。它比其它所有的語(yǔ)言更容易移植(但并非100%可移植——不同的平臺(tái)有不同問(wèn)題)。它具有垃圾收集機(jī)制,簡(jiǎn)化了內(nèi)存管理,同時(shí)也讓某些構(gòu)造如閉包可實(shí)現(xiàn)。
但是,同時(shí),Java和所有的語(yǔ)言一樣,也有瑕疵。在值語(yǔ)義的類型上缺少支持。它的同步并不是很有效率。它的標(biāo)準(zhǔn)庫(kù)建立在異常檢查之上,把實(shí)現(xiàn)拖進(jìn)了接口。它的性能可以更好。它的數(shù)學(xué)庫(kù)有些惱人的問(wèn)題。諸如此類。
這些缺憾都是大問(wèn)題嗎?看你用它做什么。因此,在幾種語(yǔ)言里,連同它的編譯器以及可以選擇的類庫(kù)里選擇對(duì)你的工程有利的一種。
[林杰杰翻譯,不是我(Chipset)譯,我僅僅是拷貝林杰杰的!]
總結(jié)
- 上一篇: python:小乌龟turtle
- 下一篇: 工作好找吗?