why the `fp.readline()` and `while line:` business?
I don't have a big file handy to benchmark but that pattern moves the file reading into python bytecode.
The canonical way to read a file line by line while counting the lines is to loop over the file (it's automatically a line iterator) and use enumerate.
here is the disassembed bytecode of the respective versions
https://pastebin.com/Rd4g8cE2
that being said, Rust will still outrun Python overall.