Search code examples
pythonconcurrent.futures

ThreadPoolExecutor Not Using Multiple Workers When Being Called Inside a Function


I'm trying to make a module that scans a given IP address and returns true or false for each port depending on it's current state. It works fine when the context manager is called by itself but when it's called within a function it stops using all of it's allocated threads. Here is my code:

import socket
import concurrent.futures

def _scan(ip, port):
    scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    scanner.settimeout(1)
    try:
        scanner.connect((ip, port))
        scanner.close()
        return True
    except:
        return False

def portScan(ip, workers, portNum):
    with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
        for port in range(portNum):
            future = executor.submit(_scan, ip, port + 1)
            print(future.result())

portScan("1.1.1.1", 100, 1000)

Solution

  • The problem is that you are waiting for each future to complete before submitting the next. You could use map instead. It will fan out the work to all of the threads and iterate the results in the same order as the parameters submitted.

    import socket
    import concurrent.futures
    
    def _scan(params):
        ip, port = params
        scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        scanner.settimeout(1)
        try:
            scanner.connect((ip, port))
            scanner.close()
            return True
        except:
            return False
    
    
    def portScan(ip, workers, portNum):
        with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
            for result in executor.map(_scan, ((ip, port) for port in range(portNum))):
                print(result)
    
    portScan("127.0.0.1", 5, 22)