Tôi tình cờ thấy Xamarin tuyên bố rằng việc triển khai Mono của họ trên Android và các ứng dụng được biên dịch C # của họ nhanh hơn mã Java. Có ai thực hiện các điểm chuẩn thực tế trên mã Java và C # rất giống nhau trên các nền tảng Android khác nhau để xác minh các khiếu nại đó, có thể đăng mã và kết quả không?
Đã thêm ngày 18 tháng 6 năm 2013
Vì không có câu trả lời và không thể tìm thấy điểm chuẩn như vậy được thực hiện bởi những người khác, nên đã quyết định làm bài kiểm tra của riêng tôi. Thật không may, câu hỏi của tôi vẫn bị "khóa" vì vậy tôi không thể đăng câu hỏi này làm câu trả lời, chỉ chỉnh sửa câu hỏi. Hãy bỏ phiếu để mở lại câu hỏi này. Đối với C #, tôi đã sử dụng Xamarin.Android Ver. 4.7.09001 (beta). Mã nguồn, tất cả dữ liệu tôi đã sử dụng để kiểm tra và các gói APK được biên dịch đều có trên GitHub:
Java: https://github.com/gregko/TtsSetup_Java
C #: https://github.com/gregko/TtsSetup_C_sharp
Nếu ai đó muốn lặp lại thử nghiệm của tôi trên các thiết bị hoặc trình giả lập khác, tôi cũng muốn tìm hiểu kết quả.
Kết quả từ thử nghiệm của tôi
Tôi đã chuyển lớp trình trích xuất câu của mình sang C # (từ ứng dụng @Voice Aloud Reader của tôi) và chạy một số bài kiểm tra trên 10 tệp HTML bằng tiếng Anh, tiếng Nga, tiếng Pháp, tiếng Ba Lan và tiếng Séc. Mỗi lần chạy được thực hiện 5 lần trên tất cả 10 tệp và tổng thời gian cho 3 thiết bị khác nhau và một trình giả lập được đăng bên dưới. Tôi chỉ thử nghiệm các bản dựng "Phát hành" mà không bật gỡ lỗi.
HTC Nexus One Android 2.3.7 (API 10) - ROM CyanogenMod
Java: Tổng thời gian lớn (5 lần chạy): 12361 ms, với tổng số lần đọc tệp: 13304 ms
C #: Tổng thời gian lớn (5 lần chạy): 17504 ms, với tổng số lần đọc tệp: 17956 ms
Samsung Galaxy S2 SGH-I777 (Android 4.0.4, API 15) - ROM CyanogenMod
Java: Tổng thời gian lớn (5 lần chạy): 8947 ms, với tổng số lần đọc tệp: 9186 ms
C #: Tổng thời gian lớn (5 lần chạy): 9884 ms, với tổng số lần đọc tệp: 10247 ms
Samsung GT-N7100 (Android 4.1.1 JellyBean, API 16) - ROM Samsung
Java: Tổng thời gian lớn (5 lần chạy): 9742 ms, với tổng số lần đọc tệp: 10111 ms
C #: Tổng thời gian lớn (5 lần chạy): 10459 ms, với tổng số lần đọc tệp: 10696 ms
Trình giả lập - Intel (Android 4.2, API 17)
Java: Tổng thời gian lớn (5 lần chạy): 2699 ms, với tổng số lần đọc tệp: 3127 ms
C #: Tổng thời gian lớn (5 lần chạy): 2049 ms, với tổng số lần đọc tệp: 2182 ms
Trình giả lập - Intel (Android 2.3.7, API 10)
Java: Tổng thời gian lớn (5 lần chạy): 2992 ms, với tổng số lần đọc tệp: 3591 ms
C #: Tổng thời gian lớn (5 lần chạy): 2049 ms, với tổng số lần đọc tệp: 2257 ms
Trình giả lập - Arm (Android 4.0.4, API 15)
Java: Tổng thời gian lớn (5 lần chạy): 41751 ms, với tổng số lần đọc tệp: 43866 ms
C #: Tổng thời gian lớn (5 lần chạy): 44136 ms, với tổng số lần đọc tệp: 45109 ms
Thảo luận ngắn
Mã kiểm tra của tôi chứa chủ yếu là phân tích cú pháp văn bản, thay thế và tìm kiếm Regex, có lẽ đối với mã khác (ví dụ: nhiều thao tác số hơn), kết quả sẽ khác. Trên tất cả các thiết bị có bộ xử lý ARM, Java hoạt động tốt hơn mã Xamarin C #. Sự khác biệt lớn nhất là dưới Android 2.3, trong đó mã C # chạy ở mức xấp xỉ. 70% tốc độ Java.
Trên trình giả lập Intel (với công nghệ Intel HAX, trình giả lập chạy ở chế độ nhanh), mã Xamarin C # chạy mã mẫu của tôi nhanh hơn nhiều so với Java - nhanh hơn khoảng 1,35 lần. Có lẽ mã và thư viện máy ảo Mono được tối ưu hóa tốt hơn nhiều trên Intel so với trên ARM?
Chỉnh sửa ngày 8 tháng 7 năm 2013
Tôi vừa cài đặt trình giả lập Android Genymotion chạy trong Oracle VirtualBox và một lần nữa, trình này sử dụng bộ xử lý Intel gốc, không mô phỏng bộ xử lý ARM. Như với trình giả lập Intel HAX, một lần nữa C # chạy ở đây nhanh hơn nhiều. Đây là kết quả của tôi:
Trình giả lập genymotion - Intel (Android 4.1.1, API 16)
Java: Tổng thời gian lớn (5 lần chạy): 2069 ms, với tổng số lần đọc tệp: 2248 ms
C #: Tổng thời gian lớn (5 lần chạy): 1543 ms, với tổng số lần đọc tệp: 1642 ms
Sau đó tôi nhận thấy rằng đã có bản cập nhật cho Xamarin.Android beta, phiên bản 4.7.11, với các ghi chú phát hành đề cập đến một số thay đổi trong thời gian chạy Mono. Quyết định nhanh chóng thử nghiệm một số thiết bị ARM và điều ngạc nhiên lớn - số C # được cải thiện:
BN Nook XD +, ARM (Android 4.0)
Java: Tổng thời gian lớn (5 lần chạy): 8103 ms, với tổng số lần đọc tệp: 8569 ms
C #: Tổng thời gian lớn (5 lần chạy): 7951 ms, với tổng số lần đọc tệp: 8161 ms
Ồ C # bây giờ tốt hơn Java? Quyết định lặp lại thử nghiệm trên Galaxy Note 2 của tôi:
Samsung Galaxy Note 2 - ARM (Android 4.1.1)
Java: Tổng thời gian lớn (5 lần chạy): 9675 ms, với tổng số lần đọc tệp: 10028 ms
C #: Tổng thời gian lớn (5 lần chạy): 9911 ms, với tổng số lần đọc tệp: 10104 ms
Ở đây C # dường như chỉ chậm hơn một chút, nhưng những con số này đã cho tôi tạm dừng: Tại sao thời gian dài hơn trên Nook HD +, mặc dù Note 2 có bộ xử lý nhanh hơn? Câu trả lời: chế độ tiết kiệm điện. Trên Nook, nó đã bị vô hiệu hóa, trên Note 2 - được bật. Quyết định kiểm tra với chế độ tiết kiệm năng lượng bị vô hiệu hóa (như đã bật, nó cũng giới hạn tốc độ bộ xử lý):
Samsung Galaxy Note 2 - ARM (Android 4.1.1), vô hiệu hóa tiết kiệm năng lượng
Java: Tổng thời gian lớn (5 lần chạy): 7153 ms, với tổng số lần đọc tệp: 7459 ms
C #: Tổng thời gian lớn (5 lần chạy): 6906 ms, với tổng số lần đọc tệp: 7070 ms
Bây giờ, thật đáng ngạc nhiên, C # cũng nhanh hơn một chút so với Java trên bộ xử lý ARM. Cải tiến lớn!
Chỉnh sửa ngày 12 tháng 7 năm 2013
Tất cả chúng ta đều biết rằng không có gì vượt qua mã gốc về tốc độ và tôi không hài lòng với hiệu suất của trình phân tách câu trong Java hoặc C #, đặc biệt là tôi cần cải thiện nó (và do đó làm cho nó chậm hơn). Quyết định viết lại nó trong C ++. Đây là một tập hợp nhỏ (tức là một tập hợp nhỏ hơn so với các thử nghiệm trước đây, vì lý do khác) so sánh tốc độ của bản gốc so với Java trên Galaxy Note 2 của tôi, với chế độ tiết kiệm năng lượng bị tắt:
Java: Tổng thời gian lớn (5 lần chạy): 3292 ms, với tổng số lần đọc tệp: 3454 ms
Ngón tay cái gốc: Tổng thời gian lớn (5 lần chạy): 537 ms, với tổng số lần đọc tệp: 657 ms
Cánh tay gốc: Tổng thời gian lớn (5 lần chạy): 458 ms, với tổng số lần đọc tệp: 587 ms
Hình như đối với thử nghiệm cụ thể của tôi, mã gốc nhanh hơn Java từ 6 đến 7 lần. Hãy cẩn thận: không thể sử dụng lớp std :: regex trên Android, do đó phải viết các thói quen chuyên biệt của riêng tôi để tìm kiếm các đoạn văn hoặc thẻ html. Các thử nghiệm ban đầu của tôi về cùng một mã trên PC sử dụng regex, nhanh hơn khoảng 4 đến 5 lần so với Java.
Phù! Đánh thức bộ nhớ thô với con trỏ char * hoặc wchar * một lần nữa, tôi ngay lập tức cảm thấy mình trẻ hơn 20 tuổi! :)
Chỉnh sửa ngày 15 tháng 7 năm 2013
(Vui lòng xem bên dưới, với các chỉnh sửa vào ngày 30 tháng 7 năm 2013, để có kết quả tốt hơn nhiều với Dot42)
Với một số khó khăn, tôi đã quản lý để chuyển các bài kiểm tra C # của mình sang Dot42 (phiên bản 1.0.1.71 beta), một nền tảng C # khác cho Android. Kết quả sơ bộ cho thấy mã Dot42 chậm hơn khoảng 3 lần (3 lần) so với Xamarin C # (v. 4.7.11), trên trình giả lập Android của Intel. Một vấn đề là lớp System.Text.RegularExpressions trong Dot42 không có hàm Split () mà tôi đã sử dụng trong các thử nghiệm Xamarin, vì vậy tôi đã sử dụng lớp Java.Util.Regex và Java.Util.Regex.Potype.Split () , vì vậy ở vị trí đặc biệt này trong mã, có sự khác biệt nhỏ này. Không nên là một vấn đề lớn mặc dù. Dot42 biên dịch thành mã Dalvik (DEX), do đó, nó hợp tác với Java trên Android, không cần sự can thiệp đắt tiền từ C # sang Java như Xamarin.
Để so sánh, tôi cũng chạy thử nghiệm trên các thiết bị ARM - ở đây mã Dot42 "chỉ" chậm hơn 2 lần so với Xamarin C #. Đây là kết quả của tôi:
HTC Nexus One Android 2.3.7 (ARM)
Java: Tổng thời gian lớn (5 lần chạy): 12187 ms, với tổng số lần đọc tệp: 13200 ms
Xamarin C #: Tổng thời gian lớn (5 lần chạy): 13935 ms, với tổng số lần đọc tệp: 14465 ms
Dot42 C #: Tổng thời gian lớn (5 lần chạy): 26000 ms, với tổng số lần đọc tệp: 27168 ms
Samsung Galaxy Note 2, Android 4.1.1 (ARM)
Java: Tổng thời gian lớn (5 lần chạy): 6895 ms, với tổng số lần đọc tệp: 7275 ms
Xamarin C #: Tổng thời gian lớn (5 lần chạy): 6466 ms, với tổng số lần đọc tệp: 6720 ms
Dot42 C #: Tổng thời gian lớn (5 lần chạy): 11185 ms, với tổng số lần đọc tệp: 11843 ms
Trình giả lập Intel, Android 4.2 (x86)
Java: Tổng thời gian lớn (5 lần chạy): 2389 ms, với tổng số lần đọc tệp: 2770 ms
Xamarin C #: Tổng thời gian lớn (5 lần chạy): 1748 ms, với tổng số lần đọc tệp: 1933 ms
Dot42 C #: Tổng thời gian lớn (5 lần chạy): 5150 ms, với tổng số lần đọc tệp: 5459 ms
Đối với tôi, thật thú vị khi lưu ý rằng Xamarin C # nhanh hơn một chút so với Java trên thiết bị ARM mới hơn và chậm hơn một chút trên Nexus One cũ. Nếu bất cứ ai cũng muốn chạy các thử nghiệm này, vui lòng cho tôi biết và tôi sẽ cập nhật các nguồn trên GitHub. Sẽ rất thú vị khi xem kết quả từ một thiết bị Android thực sự với bộ xử lý Intel.
Cập nhật ngày 26/07/2013
Chỉ cần một bản cập nhật nhanh, được biên dịch lại bởi các ứng dụng điểm chuẩn với Xamarin.Android 4.8 mới nhất và cũng với bản cập nhật dot42 1.0.1.72 được phát hành hôm nay - không có thay đổi đáng kể so với kết quả được báo cáo trước đó.
Cập nhật ngày 30 tháng 7 năm 2013 - kết quả tốt hơn cho dot42
Đã kiểm tra lại Dot42 với cổng của Robert (từ các nhà sản xuất dot42) mã Java của tôi sang C #. Trong cổng C # ban đầu được thực hiện cho Xamarin, tôi đã thay thế một số lớp Java nguyên gốc, như ListArray, với lớp List có nguồn gốc từ C #, v.v. Robert không có mã nguồn Dot42 của tôi, vì vậy anh ta đã chuyển nó một lần nữa từ Java và sử dụng các lớp Java gốc trong Những nơi như vậy, có lợi cho Dot42, tôi đoán vì nó chạy trong Dalvik VM, như Java chứ không phải ở Mono, như Xamarin. Bây giờ kết quả Dot42 tốt hơn nhiều. Đây là một bản ghi từ thử nghiệm của tôi:
30/07/2013 - Thử nghiệm Dot42 với nhiều lớp Java hơn trong Dot42 C #
Trình giả lập Intel, Android 4.2
Dot42, Mã của Greg sử dụng StringBuilder.Replace () (như trong Xamarin):
Tổng thời gian lớn (5 lần chạy): 3646 ms, với tổng số lần đọc tệp: 3830 msDot42, Mã của Greg sử dụng String.Replace () (như mã của Java và Robert):
Tổng thời gian lớn (5 lần chạy): 3027 ms, với tổng số lần đọc tệp: 3206 msDot42, Mã của Robert:
Tổng thời gian lớn (5 lần chạy): 1781 ms, với tổng số lần đọc tệp: 1999 msXamarin:
Tổng thời gian lớn (5 lần chạy): 1373 ms, với tổng số lần đọc tệp: 1505 msJava:
Tổng thời gian lớn (5 lần chạy): 1841 ms, với tổng số lần đọc tệp: 2044 msARM, Samsung Galaxy Note 2, tiết kiệm năng lượng, Android 4.1.1
Dot42, Mã của Greg sử dụng StringBuilder.Replace () (như trong Xamarin):
Tổng thời gian lớn (5 lần chạy): 10875 ms, với tổng số lần đọc tệp: 11280 msDot42, Mã của Greg sử dụng String.Replace () (như mã của Java và Robert):
Tổng thời gian lớn (5 lần chạy): 9710 ms, với tổng số lần đọc tệp: 10097 msDot42, Mã của Robert:
Tổng thời gian lớn (5 lần chạy): 6279 ms, với tổng số lần đọc tệp: 6622 msXamarin:
Tổng thời gian lớn (5 lần chạy): 6201 ms, với tổng số lần đọc tệp: 6476 msJava:
Tổng thời gian lớn (5 lần chạy): 7141 ms, với tổng số lần đọc tệp: 7479 ms
Tôi vẫn nghĩ rằng Dot42 còn một chặng đường dài. Có các lớp giống như Java (ví dụ ArrayList) và hiệu năng tốt với chúng sẽ giúp việc chuyển mã từ Java sang C # dễ dàng hơn một chút. Tuy nhiên, đây là điều mà tôi sẽ không thể làm được nhiều. Tôi muốn sử dụng mã C # hiện tại (thư viện, v.v.), sẽ sử dụng các lớp C # gốc (ví dụ: Danh sách) và sẽ hoạt động chậm với mã dot42 hiện tại và rất tốt với Xamarin.
Greg