day30work

GIl Global Interpreter Lock

Python Python code executed by a virtual machine (also called the interpreter main loop) controlled. Python early in the design should take into account the main loop, while only one thread execution. While the Python interpreter can "run" multiple threads, but only one thread running in the interpreter at any time.

Access to the Python virtual machine is controlled by the Global Interpreter Lock (GIL), it is this lock ensures that only one thread is running.

In a multithreaded environment, Python virtual machine executes the following manner:

  1. Set GIL;
  2. Switch to a thread to run;
  3. A specified number of byte code instructions or thread initiative to the control (can be called time.sleep (0));
  4. The threads to sleep;
  5. Unlock GIL;
  6. Repeat all the above steps again.

GIL is the essence of a mutex, the purpose to prevent multiple threads within the same process execution (parallel) at the same time (multiple threads in a single process can not be achieved in parallel, but it can achieve concurrent), mainly because of the lock CPython memory manager is not "thread safe", in order to ensure the presence of GIL is thread-safe, over multiple threads execute in the event of IO operations, it will immediately release the GIL interpreter lock, to advanced to the next thread

import time
from threading import Thread, current_thread

number = 100

def task():
    global number
    number2 = number
    time.sleep(2)
    number = number2 - 1
    print(number, current_thread().name)


for line in range(10):
    t = Thread(target=task)
    t.start()

Multithreading role

多线程的作用:
    站在两个角度去看问题:

    - 四个任务, 计算密集型, 每个任务需要10s:
        单核:
            - 开启进程
                消耗资源过大
                - 4个进程: 40s

            - 开启线程
                消耗资源远小于进程
                - 4个线程: 40s

        多核:
            - 开启进程
                并行执行,效率比较高
                - 4个进程: 10s

            - 开启线程
                并发执行,执行效率低.
                - 4个线程: 40s



    - 四个任务, IO密集型, 每个任务需要10s:
        单核:
            - 开启进程
                消耗资源过大
                - 4个进程: 40s

            - 开启线程
                消耗资源远小于进程
                - 4个线程: 40s

        多核:
            - 开启进程
                并行执行,效率小于多线程,因为遇到IO会立马切换CPU的执行权限
                - 4个进程: 40s  +  开启进程消耗的额外时间

            - 开启线程
                并发执行,执行效率高于多进程

                - 4个线程: 40s
'''
总结:
单核情况下:
    使用线程
多核情况下:  
    在计算密集型的情况下:
        使用多进程(可以并行执行)
    
    在IO密集型的情况下:
        使用多线程(遇到IO操作,线程切换的效率比进程切换的效率快的多)
    
高效执行多个进程,内多个IO密集型的程序:
    使用 多进程 + 多线程
'''               

Deadlock

from threading import Lock, Thread, current_thread
import time

mutex_a = Lock()
mutex_b = Lock()
#
# print(id(mutex_a))
# print(id(mutex_b))

class MyThread(Thread):

    # 线程执行任务
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        mutex_a.acquire()
        # print(f'用户{current_thread().name}抢到锁a')
        print(f'用户{self.name}抢到锁a')
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')
        mutex_a.release()
        print(f'用户{self.name}释放锁a')

    def func2(self):
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        # IO操作
        time.sleep(1)

        mutex_a.acquire()
        print(f'用户{self.name}抢到锁a')
        mutex_a.release()
        print(f'用户{self.name}释放锁a')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')
        
for line in range(10):
    t = MyThread()
    t.start()        
'''        
>>>
用户Thread-1抢到锁a
用户Thread-1抢到锁b
用户Thread-1释放锁b
用户Thread-1释放锁a
----以上是第一个进程的正常执行
用户Thread-1抢到锁b(遇到IO,进入阻塞)用户Thread-2抢到锁a(执行第二个线程)
''''''

Recursive lock

class MyThread(Thread):

    # 线程执行任务
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        print(1111)
        mutex_a.acquire()
        print(f'用户{self.name}抢到锁a')

        # mutex_a.release()
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')
        # mutex_a.release()
        # print(f'用户{self.name}释放锁a')

    def func2(self):
        mutex_b.acquire()
        print(f'用户{self.name}抢到锁b')
        # IO操作
        time.sleep(1)
        mutex_a.acquire()
        print(f'用户{self.name}抢到锁a')
        mutex_a.release()
        print(f'用户{self.name}释放锁a')
        mutex_b.release()
        print(f'用户{self.name}释放锁b')


for line in range(10):
    t = MyThread()
    t.start()
    
'''
111
用户Thread-1抢到锁a(线程1的锁a没有释放)
用户Thread-1抢到锁b
用户Thread-1释放锁b
用户Thread-1抢到锁b(遇到IO,执行另外的线程)
111 (输出111说明另外的线程执行了,但是递归锁不能使用)
111
111
111
111
111
111
111
111
用户Thread-1抢到锁a(线程1的func2)
用户Thread-1释放锁a
用户Thread-1释放锁b
'''    

signal source

from threading import Semaphore, Lock
from threading import current_thread
from threading import Thread
import time

sm = Semaphore(5)

def task():
    # mutex.acquire()
    sm.acquire()
    print(f'{current_thread().name}执行任务')
    time.sleep(2)
    sm.release()
    # mutex.release()
    # print(111)
#

for line in range(20):
    t = Thread(target=task)
    t.start()
    
'''
Thread-1执行任务
Thread-2执行任务
Thread-3执行任务
Thread-4执行任务
Thread-5执行任务
(sleep(2))
Thread-6执行任务
Thread-7执行任务
Thread-8执行任务
Thread-10执行任务
Thread-9执行任务
(sleep(2))
Thread-11执行任务
Thread-12执行任务Thread-13执行任务
Thread-15执行任务
Thread-14执行任务
(sleep(2))
Thread-16执行任务
Thread-17执行任务
Thread-19执行任务Thread-18执行任务

Thread-20执行任务
'''    

Thread queue

FIFO: FIFO queue

LIFO: Last In First Out queue

Priority Queue: output order determined according to the ASCII code

import queue

#FIFO队列
q = queue.Queue()
#Lifo队列
q = queue.LifoQueue()
#优先级队列,传入元组参数,根据元组元素的ASCii码顺序决定输入顺序
q = queue.PriorityQueue()

q.put((4,'a优', '先', '娃娃头', 4)) 
q.put((3,'a先', '优', '娃娃头', 3))  
q.put((2,'a级', '级', '娃娃头', 2))  

print(q.get())  #第一个元素为2的元组

Guess you like

Origin www.cnblogs.com/shenblog/p/11728472.html