'Multithreading in Python does not give the expected performance

I am building an application to solve Matrices in Linear Algebra. I have this class:

class Matrix:
def __init__(self):
    self.elements = []
    self.height = 0
    self.width = 0

def __add__(self, matrix):
    resultant_matrix = []
    row = []
    for i in range(self.height):
        row.clear()
        for j in range(self.width):
            row.insert(j, self.elements[i][j] + matrix.elements[i][j])
        resultant_matrix.insert(i, row)
    return self.list_to_object(resultant_matrix)

@staticmethod
def list_to_object(list_matrix):
    matrix_obj = Matrix()
    matrix_obj.elements = list_matrix
    matrix_obj.height = len(list_matrix)
    matrix_obj.width = len(list_matrix[0])
    return matrix_obj

@classmethod
def get_matrix(cls, rows=3, columns=3):
    mat = Matrix()
    for i in range(rows):
        row = []
        for j in range(columns):
            row.append(j)
        mat.elements.append(row)
    mat.height = len(mat.elements)
    mat.width = len(mat.elements[0])
    return mat

My focus is on the add method that helps me to add to matrices.

I have a method in the following class addition to split the matrices into smaller parts, then do the addition process on them, then reassemble them and return the new matrix.

class ThreadingManager:
threads = []
maximum_available_threads = 8

def do_add(self, slice1, slice2, index, _list):
    m1 = Matrix.list_to_object(slice1)
    m2 = Matrix.list_to_object(slice2)
    elements = (m1 + m2).elements
    for i, row in enumerate(elements):
        _list[index+i] = row

def addition(self, matrix_a, matrix_b):
    m1 = matrix_a.elements
    m2 = matrix_b.elements

    parts_number = self.maximum_available_threads

    sub_matrices_m2 = get_sub_matrix(m1, parts_number)
    sub_matrices_m3 = get_sub_matrix(m2, parts_number)
    new_list = [[] * matrix_a.width] * matrix_a.height

    for i in range(len(sub_matrices_m2)):
        sub_matrices_m2_i = sub_matrices_m2[i]
        sub_matrices_m3_i = sub_matrices_m3[i]
        rows_number_per_thread = i*len(sub_matrices_m2_i)
        thread = threading.Thread(target=self.do_add, args=(sub_matrices_m2_i, sub_matrices_m3_i,
                                                            rows_number_per_thread, new_list))
        thread.start()
        self.threads.append(thread)

    for thread in self.threads:
        thread.join()
        self.threads.remove(thread)
    return Matrix.list_to_object(new_list)

Finally, I have this test case (You can change the 50000 to any number, depending on your computer resources)

mat_a = Matrix.get_matrix(50000, 5)
mat_b = Matrix.get_matrix(50000, 5)

start = datetime.now()
mat_c = mat_a + mat_b
end = datetime.now()
print('time needed before multithreading is:', end - start)

start = datetime.now()
result = ThreadingManager().addition(mat_a, mat_b)
end = datetime.now()
print('time needed before multithreading is:', end - start)

My problem is that I cannot find any difference between the normal addition and multithreading. How can I use multithreading in a better way?

Note: If I removed the line row.clear() in the Matrix class, I have a wrong answer but I can notice the differences after multithreading

needed imports

import math
import threading
from datetime import datetime


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source