1

I want to know how many data has been downloaded in the last 1 second.
I don't have a code yet but I was wondering when I should start counting this 1 second and how to do it.
Should I start counting before retrbinary() or after? Or am I totally wrong?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Aspect013
  • 43
  • 8
  • can you post the code where you download the the file? – Claudio Sep 13 '19 at 13:12
  • Generally you have a loop that reads `x` amount of bytes of data, just check how long every iteration (or ten or whatever) takes and then its just calculations – Artog Sep 13 '19 at 13:14
  • This looks like [XY problem](https://meta.stackexchange.com/q/66377/218578). I assume that what you actually want to implement is a a transfer speed display. – Martin Prikryl Sep 13 '19 at 13:32
  • @Artog well how would the loop work? Let's say I have this line of code: `ftp.retrbinary('RETR ' + readme.txt, 8192)` Where do I loop through the `x` amount of bytes? @MartinPrikryl and yes I want to implement transfer speed display. – Aspect013 Sep 13 '19 at 14:09

1 Answers1

1

First, there are ready-made implementations for transfer progress display, including the transfer speed.

For an example, the progressbar2 module. See Show FTP download progress in Python (ProgressBar).

The progressbar2 by default displays FileTransferSpeed widget, what is an average transfer speed since the download started.

Though note that speed displays usually do not show such speed. They display an average speed over last few seconds. That makes the value more informative. The progressbar2 has AdaptiveTransferSpeed widget for that. But it seems to be broken.


If you want to implement the calculation on your own, and are happy with the simple average transfer speed since the download started, it is easy:

from ftplib import FTP
import time
import sys
import datetime

ftp = FTP(host, user, passwd)

print("Downloading")
total_length = 0
start_time = datetime.datetime.now()

def write(data):
   f.write(data)
   global total_length
   global start_time
   total_length += sys.getsizeof(data)
   elapsed = (datetime.datetime.now() - start_time)
   speed = (total_length / elapsed.total_seconds())
   print("\rElapsed: {0} Speed: {1:.2f} kB/s".format(str(elapsed), speed / 1024), end="")

f = open('file.dat', 'wb')
ftp.retrbinary("RETR /file.dat", write)
f.close()

print()
print("done")    

It is a way more difficult to calculate the average speed in the last seconds. You have to remember the amount of data transferred at past moments. Stealing (and fixing) the code from AdaptiveTransferSpeed, you will get something like:

sample_times = []
sample_values = []
INTERVAL = datetime.timedelta(milliseconds=100)
last_update_time = None
samples=datetime.timedelta(seconds=2)
total_length = 0

def write(data):
   f.write(data)

   global total_length

   total_length += sys.getsizeof(data)
   elapsed = (datetime.datetime.now() - start_time)

   if sample_times:
       sample_time = sample_times[-1]
   else:
       sample_time = datetime.datetime.min

   t = datetime.datetime.now()
   if t - sample_time > INTERVAL:
       # Add a sample but limit the size to `num_samples`
       sample_times.append(t)
       sample_values.append(total_length)

       minimum_time = t - samples
       minimum_value = sample_values[-1]
       while (sample_times[2:] and
              minimum_time > sample_times[1] and
              minimum_value > sample_values[1]):
           sample_times.pop(0)
           sample_values.pop(0)

   delta_time = sample_times[-1] - sample_times[0]
   delta_value = sample_values[-1] - sample_values[0]
   if delta_time:
       speed = (delta_value / delta_time.total_seconds())

       print("\rElapsed: {0} Speed: {1:.2f} kB/s".format(
           str(elapsed), speed / 1024), end="")

ftp.retrbinary("RETR /medium.dat", write)
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Wait so what is immediate speed? Your code is working but I don't understand what is "immediate speed". My goal was to create a transfer speed display like when you download a game on Steam or a file in Chrome, it shows the current download speed. That is immediate speed or an average transfer speed? – Aspect013 Sep 14 '19 at 11:45
  • The code calculates `bytes-downloaded-since-start/second-since-start`. I do not know what Steam algorithm is, but I believe that most speed displays do something like `bytes-downloaded-in-last-X-seconds/X`. The `X` would be something like 2–5 seconds. [`AdaptiveTransferSpeed` widget](https://progressbar-2.readthedocs.io/en/latest/_modules/progressbar/widgets.html#AdaptiveTransferSpeed) from [`progressbar2` library](https://pypi.org/project/progressbar2/) uses `X=2` by default. – Martin Prikryl Sep 14 '19 at 14:36
  • If it shows the `bytes-downloaded-since-start/seconds-since-starts` then why it shows it downloaded 3500 kB when I'm downloading 102 MB file? – Aspect013 Sep 14 '19 at 15:46
  • I do not understand. My code shows a speed in `kB/s`, not a number of downloaded bytes in `kB`. – Martin Prikryl Sep 14 '19 at 16:15
  • Mine does it too but you said it's `bytes-downloaded-since-start`. It shows `kB/s` in my console also but as you said these are the bytes downloaded since the start? – Aspect013 Sep 14 '19 at 18:31
  • No I wrote that the code calculates `bytes-downloaded-since-start` **divided by** `seconds-since-start`. – Martin Prikryl Sep 14 '19 at 20:13
  • Oh okay. I misunderstood. I looked at the docs and I also noticed that It's a widget the AdaptiveTransferSpeed one. Can I print the transfer speed from this widget? And how? – Aspect013 Sep 14 '19 at 21:03
  • I've rewritten my answer. – Martin Prikryl Sep 16 '19 at 11:07
  • Okay it works without any problems and thank you very much but does it show the kilobytes downloaded in the last seconds? Or does it show, as you said, from the widget the kilobytes downloaded in the last 2-5 seconds? – Aspect013 Sep 17 '19 at 13:09
  • It shows average number of bytes transferred per second in the interval specified by `samples` (2 seconds in the code). – Martin Prikryl Sep 17 '19 at 13:17
  • So every 2 seconds it checks how many bytes have been transfered in the last seconds? – Aspect013 Sep 17 '19 at 13:45
  • No it checks every 100 ms (`INTERVAL`) how many bytes were downloaded in the last approximately 2 seconds (`samples`) and divides that by the same interval, so that what it displays is kB/s. – Martin Prikryl Sep 17 '19 at 13:53
  • But 1 second is 1000 miliseconds and the interval is 100 miliseconds so if I get it right, it should show `2000 ms / 100 ms` which is 20 ms so It's `kB/20ms` then, right? I'm sorry if I'm still thinking wrong. It's quite hard to understand for me. – Aspect013 Sep 17 '19 at 16:14
  • Sorry, I do not understand your problem. Do you have any reason to believe the displayed value of wrong? For me it shows the correct value, in kB/s, as the unit tells. For example, I'm transferring a file large about 350 MB, it takes about 8 seconds and the speed display fluctuates around 45000 kB/s. What is correct, as 350 * 1024 / 8 = 44800. – Martin Prikryl Sep 18 '19 at 08:50
  • Okay. Now I understand so it shows like the current download speed. E.g when you go to the speedtest.net you can test your download speed and it shows the current maximum download speed. It's the same here right? Current download speed? – Aspect013 Sep 18 '19 at 12:16
  • For the third time (at least): It shows the **average download speed per second in the last 2 seconds**. If it makes you happy, if I declare that to be the *"Current download speed"*, so OK, it is *"Current download speed"*. – Martin Prikryl Sep 18 '19 at 12:22