Setting turtle.speed() to any value, including the result of random.randint(), is neither necessary nor sufficient.  It's simply convenient.  Below is my minimalist turtle racing code.  The turtle.speed() method is used as a place to stash the turtle's speed but if you change:
turtle.forward(turtle.speed() + 1)
to a fixed value:
turtle.forward(10)
you'll see that the turtles all move at the same rate, regardless of the setting of turtle.speed().  The turtle.speed() value only determines how quickly a turtle draws its update.  Ultimately differences in the argument to turtle.forward() control the amount of forward motion:
from random import randint
from turtle import Turtle, Screen
TURTLE_SIZE = 20
MAXIMUM_SPEED = 10
DEFAULTS = {'shape':"turtle", 'visible': False}
screen = Screen()
starting_line = TURTLE_SIZE - screen.window_width()/2
finish_line = screen.window_width()/2 - TURTLE_SIZE - MAXIMUM_SPEED
turtles = dict(red=Turtle(**DEFAULTS), green=Turtle(**DEFAULTS), blue=Turtle(**DEFAULTS))
for i, (color, turtle) in enumerate(turtles.items()):
    turtle.color(color)
    turtle.penup()
    turtle.goto(starting_line, i * TURTLE_SIZE)
    turtle.speed(randint(0, MAXIMUM_SPEED))
    turtle.showturtle()
racing = True
while racing:
    for turtle in turtles.values():
        turtle.forward(turtle.speed() + 1)
        if turtle.xcor() >= finish_line:
            racing = False
            break
screen.exitonclick()
To get turtle racing that's any more sophisticated, you probably need to work with the ontimer() event to allow them to move more independently.
