I have written a class that generates random TCP ports that meet two criteria: 1, the port isn't being used by other processes; 2, the port hadn't been assigned by the object before.
To solve the problem, I created three sets, set 1 is a class attribute that won't change, it is the constant set representing all TCP ports from 1 to 65535.
Set 2 is dynamically created using a staticmethod, that contains all listening ports at the runtime of the staticmethod.
Set 3 is an instance attribute that is initially empty.
When the method that gets random ports is called, it calculates set1 - set2 - set3 and randomly chooses from the result and adds the choice to set3.
The code:
import psutil
import random
class Port_Getter:
TOTAL = set(range(1, 65536))
@staticmethod
def busyports():
return set(i.laddr.port for i in psutil.net_connections())
def __init__(self):
self.assigned = set()
def randomport(self):
available = list(Port_Getter.TOTAL - Port_Getter.busyports() - self.assigned)
port = random.choice(available)
self.assigned.add(port)
return port
It works, but it is not very performant:
In [214]: p = Port_Getter()
In [215]: %timeit [p.randomport() for i in range(32)]
144 ms ± 3.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
I understand the list
conversion is likely the culprit that slows down the function, however random.choice()
doesn't work with sets and random.sample()
with sets is deprecated and not very fast either.
Using a list
will eliminate the need of conversion for random.choice()
, however I need to either convert the lists back to sets to get the difference or use list comprehension to get the difference, both methods will slow down the code.
So what is a more efficient way to get the same results? I think it might be a third party library that can randomly choose from sets, but I really don't know what can do this.
This is not a duplicate of Python list subtraction operation, however this does indeed contain certain facets from that question.