Search code examples
pythonmultiprocessingconcurrent.futures

Concurrent.futures used, but only one core is active


I am trying to understand concurrent.futures so i wanted to create a small code example. The numbers from 1 to $10^7$ shall be summed up. I want to use 4 cores. So I created 4 lists, namely [1,5,9,13...], [2,6,10,14...], [3,7,11,...], [4,8,12,...].

But when I run my script and check the system monitor (Linux Mint 21) I see, that only one core is used. Shouldn't it be four?

Here is my code:

#!/usr/bin/python3

from multiprocessing import Pool
import time
import concurrent.futures

def computeSum(list):
    sumValue = 0
    for i in list:
        sumValue += i
    return sumValue

def computeModuloList(completeList, modulo, moduloOffset):
    # empty list
    moduloList = []
    for i in completeList:
        if i % modulo - moduloOffset == 0:
            moduloList.append(i) # append i to modulo list
    return moduloList



listToSum = range(1, 10**7+1)

partialList1 = computeModuloList(listToSum, 4, 0)
partialList2 = computeModuloList(listToSum, 4, 1)
partialList3 = computeModuloList(listToSum, 4, 2)
partialList4 = computeModuloList(listToSum, 4, 3)

partialLists = [partialList1, partialList2, partialList3, partialList4]

resultList = []

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    future = {executor.submit(computeSum, pList): pList for pList in partialLists}
    for completedFuture in concurrent.futures.as_completed(future):
        resultList.append(completedFuture.result())
            

allSum = 0
for result in resultList:
    allSum += result

print(str(allSum))

I checked the system monitor and only one core is used


Solution

  • I would go down the multiprocessing rout, but do note the answer from Codist which uses concurrent.futures.

    This is what multiprocessing would look like for the same:

    from multiprocessing import Pool
    import numpy as np
    
    
    def main():
        n = 10**7
        arr = np.arange(1, n+1)
    
        # Split into 4 arrays 
        arr1, arr2, arr3, arr4 = np.array_split(arr, 4)
    
        with Pool(4) as pool:
            res1 = pool.apply_async(sum_array, [arr1])
            res2 = pool.apply_async(sum_array, [arr2])
            res3 = pool.apply_async(sum_array, [arr3])
            res4 = pool.apply_async(sum_array, [arr4])
    
            sums = [r.get() for r in [res1, res2, res3, res4]]
        
        total = sum(sums)
        print(total)
    
    
    def sum_array(arr):
        return np.sum(arr, dtype=np.uint64)
    
    
    if __name__ == '__main__':
        main()
    
    

    the code returns this:

    50000005000000.0
    

    As a side note. I ran both methods up to 10^9 and multiprocessing was meaningfully faster (in fact concurrent.futures hung my PC).