Tribler / tribler

Privacy enhanced BitTorrent client with P2P content discovery
https://www.tribler.org
GNU General Public License v3.0
4.73k stars 445 forks source link

[7.14] Slow coroutine step execution: DownloadManager.create_session() because of default_network_utils.get_random_free_port() #8059

Open kozlovsky opened 3 weeks ago

kozlovsky commented 3 weeks ago

https://sentry.tribler.org/organizations/tribler/issues/2805/events/a3ddf619d61b4e239e1e8d53da36e7c9/

Slow coroutine execution: 16.880 seconds, 
<Task pending name='Task-9' coro=<Component.start() running at src\<relief>\core\components\component.py:42> cb=[gather.<locals>._done_callback() at C:\Users\<relief>\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py:751]>, 
Traceback (most recent call last):, 
  File "src\<relief>\core\components\component.py", line 42, in start (function started 16.880 seconds ago), 
  File "src\<relief>\core\components\libtorrent\libtorrent_component.py", line 31, in run (function started 16.880 seconds ago), 
  File "src\<relief>\core\components\libtorrent\download_manager\download_manager.py", line 150, in initialize (function started 16.880 seconds ago), 
  File "src\<relief>\core\components\libtorrent\download_manager\download_manager.py", line 340, in get_session (function started 16.878 seconds ago), 
  File "src\<relief>\core\components\libtorrent\download_manager\download_manager.py", line 261, in create_session (function started 16.878 seconds ago), 
  File "src\<relief>\core\utilities\network_utils.py", line 65, in get_random_free_port (function started 14.180 seconds ago), 
  File "src\<relief>\core\utilities\network_utils.py", line 77, in is_port_free (function started 14.179 seconds ago), 

Here:

    def create_session(self, hops=0, store_listen_port=True):
        ...
        libtorrent_port = self.config.port or default_network_utils.get_random_free_port()
        ...

So, calling default_network_utils.get_random_free_port() from the asyncio event loop can freeze the loop for tens of seconds.

It is the only remaining place where default_network_utils.get_random_free_port is still used. I believe we can allow libtorrent itself to determine the free port and ask it for the selected port after that. A second (less preferable) solution is to make get_random_free_port() async and move the free port check to the separate thread so the asyncio loop can continue its work.

sentry-for-tribler[bot] commented 3 weeks ago

Sentry issue: TRIBLER-1QX