我是Julia的新手,并且一直在试验它,因为我知道它有惊人的表现。但我仍然要体验那些承诺的表演。我已经尝试了很多提高“JULIA HIGH PERFORMANCE”一书中描述的性能的方法,这使得代码的可读性略差。但是,我的python代码比我的Julia代码快得多,至少比基准情况快了3倍。 要么我在做一些非常错误的代码,这些代码在Julia中一定是罪恶,或者Julia无法做到。请稍后证明我错了。如何让Julia代码更高效?目前它的表现甚至比Python差
我想在代码中做的是将不同的球分配到不同的盒子中,每个盒子的容量有最大和最小限制。球放置在盒子中的顺序也很重要。我需要在尽可能短的时间内用给定的约束条件生成所有可能的作业。
Python代码:
import itertools
import time
max_balls = 5
min_balls = 0
def get_assignments(balls, boxes, assignments=[[]]):
all_assignments = []
upper_ball_limit = len(balls)
if upper_ball_limit > max_balls:
upper_ball_limit = max_balls
n_boxes = len(boxes)
lower_ball_limit = len(balls) - upper_ball_limit * (n_boxes - 1)
if lower_ball_limit < min_balls:
lower_ball_limit = min_balls
if len(boxes) == 0:
raise Exception("No delivery boys found")
elif len(boxes) == 1:
for strategy in itertools.permutations(balls, upper_ball_limit):
# valid = evaluate_strategy(strategy, db_id)
for subplan in assignments:
subplan_copy = subplan[:]
box_id = boxes[0]
subplan_copy.append((box_id, strategy))
all_assignments.append(subplan_copy)
return all_assignments
else:
box_id = boxes[0]
for i in range(lower_ball_limit, upper_ball_limit+ 1):
for strategy in itertools.permutations(balls, i):
temp_plans = []
for subplan in assignments:
subplan_copy = subplan[:]
subplan_copy.append((box_id, strategy))
temp_plans.append(subplan_copy)
remaining_balls = set(balls).difference(strategy)
remaining_boxes = list(set(boxes).difference([box_id]))
if remaining_balls:
all_assignments.extend(get_assignments(remaining_balls, remaining_boxes, temp_plans))
else:
all_assignments.extend(temp_plans)
return all_assignments
balls = range(1, 9)
boxes = [1, 2, 3, 4]
t = time.time()
all_assignments = get_assignments(balls, boxes)
print('Number of assignments: %s' % len(all_assignments))
print('Time taken: %s' % (time.time()-t))
这里是我写的JULIA CODE为上述的尝试。
#!/usr/bin/env julia
using Combinatorics
const max_balls=5
const min_balls=0
function plan_assignments(balls::Vector{Int32}, boxes ; plans=[Vector{Tuple{Int32,Array{Int32,1}}}(length(boxes))])
const n_boxes = length(boxes)
const n_balls = length(balls)
const n_plans = length(plans)
if n_boxes*max_balls < n_balls
print("Invalid Inputs: Number of balls exceed the number of boxes.")
end
all_plans = Vector{Tuple{Int32,Array{Int32,1}}}[]
upper_box_limit = n_balls
if upper_box_limit > max_balls
upper_box_limit = max_balls
end
lower_box_limit = n_balls - upper_box_limit * (n_boxes-1)
if lower_box_limit < min_balls
lower_box_limit = min_balls
end
if n_boxes == 1
box_id = boxes[1]
@inbounds for strategy in Combinatorics.permutations(balls, upper_box_limit)
@inbounds for subplan in plans
subplan = subplan[:]
subplan[tn_boxes - n_boxes + 1] = (box_id, strategy)
all_plans = push!(all_plans, subplan)
end
end
return all_plans
else
box_id = boxes[1]
@inbounds for i in lower_box_limit:upper_box_limit
@inbounds for strategy in Combinatorics.permutations(balls, i)
temp_plans = Array{Vector{Tuple{Int32,Array{Int32,1}}},1}(n_plans)
# temp_plans = []
@inbounds for (i,subplan) in zip(1:n_plans, plans)
subplan = subplan[:]
subplan[tn_boxes - n_boxes + 1] = (box_id, strategy)
temp_plans[i] = subplan
# subplan = push!(subplan, (db_id, strategy))
# temp_plans = push!(temp_plans, subplan)
remaining_balls = filter((x) -> !(x in strategy), balls)
remaining_boxes = filter((x) -> x != box_id , boxes)
if length(remaining_balls) > 0
@inbounds for plan in plan_assignments(remaining_balls, remaining_boxes, plans=temp_plans)
push!(all_plans, plan)
end
# append!(all_plans, plan_assignments(remaining_orders, remaining_delivery_boys, plans=temp_plans))
else
@inbounds for plan in temp_plans
push!(all_plans, plan)
end
# append!(all_plans, temp_plans)
end
end
end
end
return all_plans
end
end
balls = Int32[1,2,3,4,5,6,7,8]
boxes = Int32[1,2,3,4]
const tn_boxes = length(boxes)
@timev all_plans = plan_assignments(balls, boxes)
print(length(all_plans))
我的基准时机如下:
对于Python:
Number of assignments: 5040000
Time taken: 22.5003659725
对于朱莉娅:(这是当贴现的编译时间)
76.986338 seconds (122.94 M allocations: 5.793 GB, 77.01% gc time)
elapsed time (ns): 76986338257
gc time (ns): 59287603693
bytes allocated: 6220111360
pool allocs: 122932049
non-pool GC allocs:10587
malloc() calls: 11
realloc() calls: 18
GC pauses: 270
full collections: 28
在垃圾收集上花费了77%的时间......看起来问题在于您正在创建大量对象。 CPython通过与GC一起使用引用计数来避免这么大的打击。请注意,77秒中的23%约为17秒,因此如果您不计算在gc中花费的时间,Julia会比CPython快。不幸的是,我不知道朱莉娅,所以我不能告诉你为什么这么多时间花在gc上。 – Bakuriu
'all_plans = push!(all_plans,subplan)'做你想做的事情吗? – daycaster
您是否需要在'subplan = subplan [:]'中获取子计划副本? –