Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow download speed of HTTPRequest node #32807

Closed
neqs20 opened this issue Oct 13, 2019 · 12 comments · Fixed by #33862
Closed

Slow download speed of HTTPRequest node #32807

neqs20 opened this issue Oct 13, 2019 · 12 comments · Fixed by #33862

Comments

@neqs20
Copy link

neqs20 commented Oct 13, 2019

Godot version:

  • v3.1.1.stable.official

OS/device including version:

  • Windows 10 x64 build: 17763.805

Issue description:

I wanted to download a file from my server ( Ubuntu Server 18.04 ) that is connected to my local network. The file has 100MB. As I found out, the best way to do this is over HTTPRequest node. The problem is with download speed. I have set up new project that prints the download speed (I included the zipped project). I have also done some tests. Here I included them:

Bandwidth: 200 Mb/s

First Test

File: From my local server.
File size: 100 MB

  • Project code:
  1. Download speed: ~2.2 MB/s
  2. Time: ~48 seconds
  3. Use threads: true
  • Browser:
  1. Download speed: ~40 MB/s
  2. Time: ~2 seconds

Second Test

File: from https://speed.hetzner.de/
File size: 100 MB

  • Project code:
  1. Download speed: ~2.0 MB/s
  2. Time: ~50 seconds
  3. Use threads: true
  • Browser:
  1. Download speed: ~4.1 MB/s
  2. Time: ~21 seconds

The difference is clearly visible.

Steps to reproduce:

  • Create new script
  • Copy and paste following code:
var done := false

var last_bytes := 0

var time := 0.0 # timer that is restarted ~every second

var http

func _ready():
	http = HTTPRequest.new()
	add_child(http)
	http.use_threads = true
	http.download_file = "100MB.bin"
	http.connect("request_completed", self, "_on_file_request_completed")

	# zip file (100 MB) from my local server 
	#http.request("http://192.168.100.104:4220/patch2.0.0.zip"

	# 100MB test file
	http.request("https://speed.hetzner.de/100MB.bin")


func _process(delta):
	if not done and time >= 1:
		var speed_in_bytes = http.get_downloaded_bytes() - last_bytes
		var speed_in_mega_bytes = speed_in_bytes / 1000000.0
		
		print(speed_in_mega_bytes, " MB/s")
		
		last_bytes = http.get_downloaded_bytes()
		time = 0
	time += delta

func _on_file_request_completed(result, response_code, headers, body):
	done = true
	print("File downloaded")
  • Attach this script to any node
  • Run it
  • Check output

Minimal reproduction project:
To import this project use the import feature at the project manager
HttpTest.zip

@Mellondill
Copy link

Same for me

@Mellondill
Copy link

Mellondill commented Oct 24, 2019

I've found some workaround, don't know if it would be suitable for you, but though here is the code that could help you:

func _process(delta):
	if resource_requested:
		var t = OS.get_ticks_msec()
		while OS.get_ticks_msec() < t + max_time_ms && resource_requested:
			$req.notification(NOTIFICATION_INTERNAL_PROCESS)

where:
$req - HTTPRequest Node
max_time_ms - max time of polling data per_frame (for my needs it was ok from 4 to 10 ms)

@neqs20
Copy link
Author

neqs20 commented Oct 28, 2019

Well, I've done some tests and it doesn't solve problem at all. I don't know what you meant Mellondill but the download speed didn't change. Could explain the code you made ?

@Mellondill
Copy link

Hello @HazmatDemon, I've tried to dive deep in classes HTTPRequest and HTTPClient, and found that actual polling of data from TCP socket is done in HTTPClient::poll() method.
HTTPClient::poll() method is called in HTTPRequest::_update_connection() method, and this method is called in HTTPRequest::_notification(int p_what) method.
Method HTTPRequest::_notification(int p_what) with argument NOTIFICATION_INTERNAL_PROCESS is called ones per frame.

Due to default read chunk size is 4096 bytes, and due to some circumstances(response headers don't contain 'content-length' attribute, etc.) that the left body length of response couldn't be determined, HTTPRequest just polls only 4096 bytes per frame.

I've just thought if I can make polling of data not per frame but in a controlled loop.

By 'controlled' I meant limiting of polling data in loop for about 5-10 milliseconds per frame, for your application to not have lags, and have stable FPS while data is polled.

So basically I'm speeding up HTTPRequest data polling, and it worked for me, and I thought that it could be suitable for you too!

@Calinou
Copy link
Member

Calinou commented Oct 29, 2019

cc @Faless

What would be a good way to solve this? Would a custom timer work for this purpose?

@Faless
Copy link
Collaborator

Faless commented Oct 29, 2019

What would be a good way to solve this? Would a custom timer work for this purpose?

I'm not sure, blocking for some milliseconds is not an option.

The repro project uses threads, and threads should poll continuously (keep blocking) so I'm not sure why this is happening.

@Faless
Copy link
Collaborator

Faless commented Oct 29, 2019

I haven't had time to investigate this further sadly

@AlexHolly
Copy link
Contributor

AlexHolly commented Nov 9, 2019

I am not able to reproduce on linux Mint
0ab0d11
Getting 5.9 MB/s in Godot and browser

On Windows
Getting 2.0 MB/s in Godot
5.5 MB/s in browser

@neqs20
Copy link
Author

neqs20 commented Nov 12, 2019

I tested it again (the same code from earlier), this time on Ubuntu and Manjaro and got 10 - 12 MB/s. It seems like Linux doesn't have problems at all.

@Faless
Copy link
Collaborator

Faless commented Nov 24, 2019

I was able to reproduce this on windows, and it seems related to the small chunk size we were using in the HTTPClient. I have exposed the property to do change it in the above PR, but we should evaluate the possibility of a better default.

@akien-mga akien-mga added this to the 3.2 milestone Nov 25, 2019
@vitorventurin
Copy link

Same issue here... any progress?

@Calinou
Copy link
Member

Calinou commented Oct 19, 2020

@vitorventurin Did you increase the download chunk size in HTTPRequest? The default is still 4 KiB, which is slow for downloading large files. See #33862.

Calinou added a commit to Calinou/godot that referenced this issue Nov 7, 2020
This improves download speeds at the cost of increased memory usage.

This change also effects HTTPRequest automatically.

See godotengine#32807 and godotengine#33862.
akien-mga pushed a commit to akien-mga/godot that referenced this issue Nov 11, 2020
This improves download speeds at the cost of increased memory usage.

This change also effects HTTPRequest automatically.

See godotengine#32807 and godotengine#33862.

(cherry picked from commit 1335709)
GryphonClaw pushed a commit to GryphonClaw/godot that referenced this issue Nov 19, 2020
This improves download speeds at the cost of increased memory usage.

This change also effects HTTPRequest automatically.

See godotengine#32807 and godotengine#33862.
HEAVYPOLY pushed a commit to HEAVYPOLY/godot that referenced this issue Dec 14, 2020
This improves download speeds at the cost of increased memory usage.

This change also effects HTTPRequest automatically.

See godotengine#32807 and godotengine#33862.

(cherry picked from commit 1335709)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants