Why are delays required in verilog with combinational logic?
It would sound like it should generate a signal as fast as it can.


Which is exactly what it does. However....

The simulator is a virtual environment. It works in 'delta' time where each delta is infinitely small in time but the deltas still happen after each other. So a simulator is (theoretically) infinitely fast. 

Thus if you remove your #.. delays your loop takes 2000 deltas, each infinitely small in time which add op to 2000*0 = zero time. (I did say it was a virtual environment).

You could compare a 'delta' with a sort of Dirac pulse: it is infinitely small. It does not exist other than in mathematical models.




  Does this mean this would work on an actual FPGA? Since an FPGA isn't infinitely fast.


No, this wil not work on an FPGA. The behavioral speed and real speed are unrelated. I often simulate with an arbitrary clock, but when I go to the FPGA I have to use an actual clock (either internal or, external). I specify the clock to the synthesis stool. The synthesis stool plus Place &amp; Route will tell me afterwards if the design will run at that clock speed. (Meet timing).

For some FPGA IP, e.g. a PLL, I must simulate with the actual clock frequency otherwise the PLL model will not work.