python - multithreading

Thread, multithreading:

  1. Thread theory:

    1. What is a thread?

      Threads are the smallest unit that the operating system can schedule operations. It is included in the process and is the actual unit of operation in the process.

    2. Processes are only used to centralize resources (processes are only a resource unit, or a collection of resources), and threads are the executing units on the cpu.

    3. Open a process space in memory, copy all the resource data of the main process, and then call the thread to execute the code.

    4. Processes are resource units and threads are execution units

  2. Thread vs process:

    1. Starting a process costs a lot more than opening a thread.

    2. The speed at which threads are opened is very fast.

    3. Threads and threads can share data, processes and processes need to use queues and other methods to achieve communication.

      from threading import Thread
      
      x = 3
      def task():
          global x
          x = 10
      
      if __name__ == '__main__':
          t1 = Thread(target=task)
          t1.start()
          t1.join()
          print(x)
      # The value of x is 10, so data can be shared in the thread.
      

      Resource data in the same process is shared among multiple threads of the process.

  3. Thread application:

    Concurrency: A cup seems to perform multiple tasks simultaneously

  4. There are two ways to open a thread:

    from threading import Thread   
    # Modules for Importing Threads
    import time
    import random
    
    def task(name):
        print(f'{name} is running')
        time.sleep(random.random())
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        t = Thread(target=task,args=('Zhou Daolong',))
        t.start()
        # Open threads
        print('----main')
    
    from threading import Thread
    import time
    import random
    
    class MyThread(Thread):
    # Define a class, inherit the Thread class, and execute some of its methods
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):    # There must be a run method
            print(f'{self.name} is running')
            time.sleep(random.random())
            print(f'{self.name} is gone')
    
    if __name__ == '__main__':
        t = MyThread('Zhou Daolong')
        t.start()
        print('----main')
    

    Its essence is to reconstruct the run method in Thread class

  5. Other methods related to threads:

    isAlive() - - Judging whether a thread is alive or not

    getName() - - Gets the thread name

    setName (Thread Name) - - Add Thread Name

    Name - - - Gets the thread name

    threading method:

    CurrentThread () - - Gets the object of the current thread (you need to import the currentThread package)

    import threading
    import time
    
    def run(arg):
        print(f'running sub thread:{threading.currentThread()}')
        threading.currentThread().name = 'task1'
        print(f'sub1 Thread...{threading.currentThread().getName()}')
        print(f'sub2 Thread...{threading.currentThread().name}')
        time.sleep(2)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=run,args=('t1',))
        t1.start()
        print(f'sub1 Thread...{threading.currentThread().getName()}')
        print(f'sub2 Thread...{threading.currentThread().name}')
    
    '''
    running sub thread:<Thread(Thread-1, started 11788)>
    sub1 Thread...MainThread
    sub1 Thread...task1
    sub2 Thread...MainThread
    sub2 Thread...task1
    '''
    

    enumerate() --------- Returns a list containing all threaded objects (need to import enumerate package)

    ActeCount () - - counting the number of threads running

    import threading
    import time
    
    def run(n):
        print(f'task{n}')
        time.sleep(1)
    
    for i in range(3):
        t = threading.Thread(target=run,args=(i,))
        t.start()
    time.sleep(1)
    print(threading.activeCount())
    
  6. join and daemon thread

    join: blocking, telling the main thread to wait for the sub-thread to finish executing before executing the main thread

    from threading import Thread
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(1)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        start_time = time.time()
        t1 = Thread(target=task,args=('Little ape',))
        t2 = Thread(target=task,args=('Little ape',))
        t3 = Thread(target=task,args=('Little ape',))
    
        t1.start()
        t1.join()
        t2.start()
        t2.join()
        t3.start()
        t3.join()
    
        print(time.time()-start_time)
    

    Daemon threads:

    from threading import Thread
    import time
    
    def task():
        print(123)
        time.sleep(2)
        print(789)
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.daemon = True
        t.start() 
        print(456)
         # Threads start very fast, so they execute task s first, and output 123.
    # Result:
    123
    456
    

    Be careful:

    from threading import Thread
    import time
    
    def foo():
        print(123)
        time.sleep(3)
        print('end123')
    
    def bar():
        print(456)
        time.sleep(3)
        print('end456')
    
    t1=Thread(target=foo)
    t2=Thread(target=foo)
    
    t1.daemon = True
    t1.start()
    t2.start()
    
    print('main-----')
    #Result:
    123
    123
    main-----
    end123
    end123
    
  7. Mutex Lock

    Because threads are randomly scheduled, when they modify one data at the same time, they generate dirty data, so there will be locks, so that only one thread can operate on the same data at the same time.

    Thread lock:

    import threading
    def run():
        global num
        num += 1   
        # Can produce data insecurity
    
    num = 0
    t_obj = []
    for i in range(50):
        t = threading.Thread(target=run)
        t.start()
        t_obj.append(t)
    
    for i in t_obj:
        i.join()
    	# Let each execution be random in sequence
    print(num)
    

Mutex:

   from threading import Thread
   from threading import Lock
   x = 100
   def task(lock):
       lock.acquire()
       global x
       tem = x
       x = tem - 1
       lock.release()

   if __name__ == '__main__':
       mutex = Lock()
       for i in range(100):
           t = Thread(target=task,args=(mutex,))
           t .start()
       print(x)

with: Automatic acquisition and release of locks in threads, etc.

So the code above can be written as follows:

   from threading import Thread,Lock
   
   x = 100
   def task(lock):
       with lock:
           global x
           tem = x
           x = tem - 1
   
   mutex = Lock()
   for i in range(100):
       t = Thread(target=task,args=(mutex,))
       t.start()
   print(x)

Added by mahrou on Fri, 23 Aug 2019 16:44:06 +0300