why multithreading in python with gil code example

Example 1: multithreading in python

from multiprocessing.pool import ThreadPool

def stringFunction(value):
    my_str = 3 + value
    return my_str


def stringFunctio(value):
    my_str = 33 + value
    return my_str



pool = ThreadPool(processes=1)

    
thread1 = pool.apply_async(stringFunction,(8,))
thread2 = pool.apply_async(stringFunctio,(8,))

return_val = thread1.get()
return_val1 = thread2.get()

Example 2: multithreading python

class FakeDatabase:
    def __init__(self):
        self.value = 0
        self._lock = threading.Lock()

    def locked_update(self, name):
        logging.info("Thread %s: starting update", name)
        logging.debug("Thread %s about to lock", name)
        with self._lock:
            logging.debug("Thread %s has lock", name)
            local_copy = self.value
            local_copy += 1
            time.sleep(0.1)
            self.value = local_copy
            logging.debug("Thread %s about to release lock", name)
        logging.debug("Thread %s after release", name)
        logging.info("Thread %s: finishing update", name)