Gần đây, tôi đã chạy vào một mã tối ưu hóa không mong muốn và muốn kiểm tra xem việc diễn giải của tôi về những gì tôi đã quan sát là chính xác hay không. Sau đây là ví dụ đơn giản hóa nhiều về tình huống:F # tổng quát và hiệu suất tự động
let demo =
let swap fst snd i =
if i = fst then snd else
if i = snd then fst else
i
[ for i in 1 .. 10000 -> swap 1 i i ]
let demo2 =
let swap (fst: int) snd i =
if i = fst then snd else
if i = snd then fst else
i
[ for i in 1 .. 10000 -> swap 1 i i ]
Sự khác biệt duy nhất giữa 2 khối mã là trong trường hợp thứ hai, tôi tuyên bố rõ ràng các đối số hoán đổi làm số nguyên. Tuy nhiên, khi tôi chạy 2 đoạn mã trong fsi với # time, tôi nhận được:
Trường hợp 1 Thực: 00: 00: 00.011, CPU: 00: 00: 00.000, GC gen0: 0, gen1: 0, gen2: 0
Trường hợp 2 Thực: 00: 00: 00.004, CPU: 00: 00: 00.015, GC gen0: 0, gen1: 0, gen2: 0
tức là đoạn thứ 2 chạy nhanh hơn 3 lần so với trước. Sự khác biệt hiệu suất tuyệt đối ở đây rõ ràng không phải là một vấn đề, nhưng nếu tôi sử dụng chức năng hoán đổi rất nhiều, nó sẽ chồng chất lên.
Giả định của tôi là lý do cho lần truy cập hiệu suất là trong trường hợp đầu tiên, hoán đổi là chung và "yêu cầu bình đẳng" và kiểm tra xem int có hỗ trợ nó hay không, trong khi trường hợp thứ hai không phải kiểm tra bất kỳ thứ gì. Đây có phải là lý do điều này đang xảy ra hay tôi đang thiếu thứ gì đó khác? Và nói chung hơn, tôi có nên xem xét việc tổng quát hóa tự động một thanh kiếm hai lưỡi, đó là một tính năng tuyệt vời có thể có tác động không mong muốn đến hiệu suất không?
Cảm ơn các con trỏ đến các câu hỏi khác, thực sự rất giống nhau. Vì vậy, nếu tôi hiểu chính xác, đánh dấu một chức năng như nội tuyến nói "trong khi chức năng này là chung chung, tạo ra một phiên bản cụ thể dựa trên các loại được sử dụng mà nó được gọi là"? Có lý do nào để không đánh dấu mọi chức năng kiểu toán học là nội tuyến không? – Mathias
Hoặc, được nêu khác đi, bạn có thể xây dựng một chút về "nó không tạo ra quá nhiều mã" không, tôi không hiểu lắm. – Mathias
@Mathias Từ khoá 'inline' có nghĩa là trình biên dịch sẽ thay thế cuộc gọi đến hàm bằng cách thực thi nó. Điều này có nghĩa là mã của hàm sẽ được lặp lại một lần cho mỗi cuộc gọi. Đối với các hàm thực sự dài, điều này có thể làm cho assembly trở nên lớn hơn (hoặc tạo ra các phương thức dài hơn mất nhiều thời gian để JIT). Đó là lý do tại sao tôi đề nghị sử dụng nó chỉ cho các hàm ngắn hơn - các hàm trong ví dụ của bạn trông khá ngắn đối với tôi. –