เป็นคำถามที่ดีมาก
การใช้งานแบบมัลติเธรดของฟังก์ชัน Fibonacci ไม่เร็วกว่าเวอร์ชั่นเธรดเดี่ยว ฟังก์ชั่นนั้นแสดงเฉพาะในโพสต์บล็อกเป็นตัวอย่างของเล่นเกี่ยวกับความสามารถในการเธรดใหม่โดยเน้นว่ามันช่วยให้วางไข่หลายเธรดในฟังก์ชั่นต่าง ๆ และตัวกำหนดตารางเวลาจะคำนวณปริมาณงานที่เหมาะสมที่สุด
ปัญหาคือว่า@spawnมีค่าใช้จ่ายที่ไม่น่ารำคาญ1µsดังนั้นถ้าคุณวางไข่เธรดเพื่อทำงานที่ใช้เวลาน้อยกว่า1µsคุณอาจทำร้ายการแสดงของคุณ ความหมายของ recursive fib(n)มีความซับซ้อนเวลาชี้แจงของการสั่งซื้อ1.6180^n[1] ดังนั้นเมื่อคุณโทรหาfib(43)คุณบางสิ่งบางอย่างเพื่อวางไข่ของ1.6180^43หัวข้อ หากแต่ละคนใช้เวลา1µsในการวางไข่จะใช้เวลาประมาณ 16 นาทีในการวางไข่และกำหนดเวลาเธรดที่ต้องการและนั่นก็ไม่ได้คำนึงถึงเวลาที่ใช้ในการคำนวณจริงและการรวมเธรด / การซิงค์อีกครั้ง เวลามากขึ้น.
สิ่งต่าง ๆ เช่นนี้ที่คุณวางไข่เธรดสำหรับแต่ละขั้นตอนของการคำนวณจะทำให้รู้สึกได้ก็ต่อเมื่อแต่ละขั้นตอนของการคำนวณใช้เวลานานเมื่อเทียบกับ@spawnค่าใช้จ่าย
โปรดทราบว่ามีงานที่จะช่วยลดค่าใช้จ่าย@spawnแต่ด้วยฟิสิกส์ของชิปซิลิโคนหลายคอร์ฉันสงสัยว่ามันจะเร็วพอสำหรับการfibใช้งานข้างต้น
หากคุณอยากรู้เกี่ยวกับวิธีที่เราสามารถปรับเปลี่ยนfibฟังก์ชั่นเธรดให้เป็นประโยชน์จริง ๆ สิ่งที่ง่ายที่สุดที่จะทำก็คือเพียงวางไข่fibเธรดถ้าเราคิดว่ามันจะใช้เวลานานกว่า1µsจะรันอย่างมีนัยสำคัญ บนเครื่องของฉัน (ทำงานบน 16 คอร์กายภาพ) ฉันได้รับ
function F(n)
if n < 2
return n
else
return F(n-1)+F(n-2)
end
end
julia> @btime F(23);
122.920 μs (0 allocations: 0 bytes)
ดังนั้นมันจึงเป็นคำสั่งที่ดีสองคำในเรื่องของการวางไข่ ดูเหมือนว่าเป็นการตัดยอดเยี่ยมที่จะใช้:
function fib(n::Int)
if n < 2
return n
elseif n > 23
t = @spawn fib(n - 2)
return fib(n - 1) + fetch(t)
else
return fib(n-1) + fib(n-2)
end
end
ตอนนี้ถ้าฉันทำตามวิธีการวัดประสิทธิภาพที่เหมาะสมด้วย BenchmarkTools.jl [2] ฉันพบ
julia> using BenchmarkTools
julia> @btime fib(43)
971.842 ms (1496518 allocations: 33.64 MiB)
433494437
julia> @btime F(43)
1.866 s (0 allocations: 0 bytes)
433494437
@Anush ถามในความคิดเห็น: นี่คือปัจจัยของ 2 ความเร็วในการใช้ 16 แกนดูเหมือนว่า เป็นไปได้หรือไม่ที่จะเพิ่มความเร็ว 16 ระดับให้เร็วขึ้น?
ใช่แล้ว. ปัญหาเกี่ยวกับฟังก์ชั่นด้านบนคือร่างกายมีขนาดใหญ่กว่าของที่Fมีเงื่อนไขจำนวนมากวางไข่ฟังก์ชัน / เธรดและทั้งหมดนั้น @code_llvm F(10) @code_llvm fib(10)ผมขอเชิญคุณที่จะเปรียบเทียบ ซึ่งหมายความว่าfibเป็นการยากสำหรับจูเลียที่จะเพิ่มประสิทธิภาพ ค่าใช้จ่ายพิเศษนี้ทำให้โลกของความแตกต่างสำหรับnกรณีเล็ก ๆ
julia> @btime F(20);
28.844 μs (0 allocations: 0 bytes)
julia> @btime fib(20);
242.208 μs (20 allocations: 320 bytes)
ไม่นะ! รหัสพิเศษทั้งหมดที่ไม่เคยสัมผัสn < 23คือการทำให้เราช้าลงด้วยลำดับความสำคัญ! มีวิธีแก้ไขที่ง่าย: เมื่อn < 23ไม่หักเงินกลับคืนให้fibโทรหาเธรดเดี่ยวFแทน
function fib(n::Int)
if n > 23
t = @spawn fib(n - 2)
return fib(n - 1) + fetch(t)
else
return F(n)
end
end
julia> @btime fib(43)
138.876 ms (185594 allocations: 13.64 MiB)
433494437
ซึ่งให้ผลลัพธ์ใกล้เคียงกับสิ่งที่เราคาดหวังสำหรับเธรดจำนวนมาก
[1] https://www.geeksforgeeks.org/time-complexity-recursive-fibonacci-program/
[2] @btimeมาโครBenchmarkTools จาก BenchmarkTools.jl จะเรียกใช้ฟังก์ชั่นหลาย ๆ ครั้งข้ามการรวบรวมเวลาและผลลัพธ์โดยเฉลี่ย