zoukankan      html  css  js  c++  java
  • 并编程复习——线程

    进程

    线程

    1、线程理论

    '''
    1、什么是线程?
        进程:资源单位
        线程:执行单位
        每个进程中自带一个线程
    2、为什么要有线程?
        开一个进程:申请内存空间  耗时
        开线程不要申请空间
        开线程的开销远小于开进程的开销
    '''
    
    
    

    2、开启线程的方式

    # 方式1
    from threading import Thread
    import time
    def task(name)
    	print('%s is running'%name)
    	time.time(sleep)
    	print('%s is over'%name)
    
    if __name__ == '__main__':
        t = Thread(target=task,args =('egon',))
    	t.start()
    	print('主')
    
    # 方式2
    from threading import Thread
    import time
    
    class MyThread(Thread)
    	def __init__(self,name):
    		super().__init__()
            self.name = name
    	def run(self)
    		print("%s is running"%s)
    		time.sleep(3)
    		print("%s is over"%s)
    if __name__ == '__main__':
    	t = Mythread('egon')
    	t.start()
    	print('主')
        
    
    • 线程之间数据共享
    from threading import Thread
    
    x = 100
    
    def task():
        global x
        x = 666
    
    t = Thread(target=task)
    t.start()
    t.join()
    print(x)
    
    
    
    • 线程互斥锁
    from threading import Thread,Lock
    import time
    import random
    
    mutex = Lock()
    n = 100
    
    def task():
        global n
        mutex.acquire()
        tmp = n
        time.sleep(0.1)
        n = tmp -1
        mutex.release()
    
    
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    
    for t in t_list:
        t.join()
    
    print(n)
    
    • 线程的其他方法
    # 守护线程
    from threading import Thread
    import time
    
    
    def task(name):
        print('%s is running'%name)
        time.sleep(1)
        print('%s is over'%name)
    
    if __name__ == '__main__':
        t = Thread(target=task,args=('王磊',))
        # t.daemon = True
        t.start()
        print('主')
    
    # 其他方法
    from threading import Thread,active_count,current_thread
    import os
    import time
    
    
    def task(name):
        # print('%s is running'%name,os.getpid())
        print('%s is running'%name,current_thread().name,current_thread().getName())
        time.sleep(1)
        print('%s is over'%name)
    
    def info(name):
        print('%s is running' % name, current_thread().name, current_thread().getName())
        time.sleep(1)
        print('%s is over' % name)
    
    t = Thread(target=task,args=('关磊',))
    t1 = Thread(target=info,args=('关超',))
    t.start()
    t1.start()
    t.join()
    print(active_count())  # 当前存活的线程数
    print(os.getpid())
    print(current_thread().name)
    print(current_thread().getName())
    
    
    

    3、GIL(全局解释器锁)

    • 什么是GIL(全局解释器锁)

      ​ 保证数据的安全(以牺牲效率来换取数据的安全),阻止同一个进程内的对个进程同时执行(不能并行但是可以是实现并发)

    • GIL存在的原因就是Python线程不是安全的(垃圾回收机制)

    问题:python多线程是不是就没有用了呢?
    四个任务:计算密集的任务 每个任务耗时10s
    单核情况下:
    多线程好一点,消耗的资源少一点
    多核情况下:
    开四个进程:10s多一点
    开四个线程:40s多一点

    四个任务:IO密集的任务 每个任务io 10s
    单核情况下:
    多线程好一点
    多核情况下:
    多线程好一点
    多线程和多进程都有自己的优点,要根据项目需求合理选择

    • GIL与普通锁的对比
    """
    对于不同的数据,要想保证安全,需要加不同的锁处理
    GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
    保证的是同一个进程下多个线程之间的安全
    """
    
    • 死锁和递归锁
    from threading import Thread,Lock,RLock
    import time
    
    """
    自定义锁一次acquire必须对应一次release,不能连续acquire
    递归锁可以连续的acquire,每acquire一次计数加一:针对的是第一个抢到我的人
    """
    import random
    #
    # mutexA = Lock()
    # mutexB = Lock()
    mutexA = mutexB = RLock()  # 抢锁之后会有一个计数 抢一次计数加一 针对的是第一个抢到我的人
    
    class MyThead(Thread):
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutexA.acquire()
            print('%s 抢到A锁了'%self.name)
            mutexB.acquire()
            print('%s 抢到B锁了' % self.name)
            mutexB.release()
            print('%s 释放了B锁'%self.name)
            mutexA.release()
            print('%s 释放了A锁'%self.name)
    
        def func2(self):
            mutexB.acquire()
            print('%s 抢到了B锁'%self.name)
            time.sleep(1)
            mutexA.acquire()
            print('%s 抢到A锁了' % self.name)
            mutexA.release()
            print('%s 释放了A锁' % self.name)
            mutexB.release()
            print('%s 释放了B锁' % self.name)
    
    
    for i in range(100):
        t = MyThead()
        t.start()
    
    
    • 线程queue
    import queue
    
    # 1.普通q
    # 2.先进后出q
    # 3.优先级q
    
    #普通q
    # q=queue.Queue(3)
    # q.put(1)
    # q.put(2)
    # q.put(3)
    # print(q.get())
    # print(q.get())
    # print(q.get())
    
    # 先进后出q
    # q = queue.LifoQueue(5)
    # q.put(1)
    # q.put(2)
    # q.put(3)
    # q.put(4)
    # print(q.get())
    
    
    
    # 优先级q
    # q = queue.PriorityQueue()
    # q.put((10,'a'))
    # q.put((-1,'b'))
    # q.put((100,'c'))
    # print(q.get())
    # print(q.get())
    # print(q.get())
    
    
    
    • 信号量
    from threading import Thread,Semaphore
    import time
    import random
    sm = Semaphore(5)  # 五个厕所五把锁
    # 跟你普通的互斥锁区别在于,普通的互斥锁是独立卫生间,所有人抢一把锁
    # 信号量 公共卫生间 有多个坑,所有人抢多把锁
    
    
    
    def task(name):
        sm.acquire()
        print('%s正在蹲坑'%name)
        # 模拟蹲坑耗时
        time.sleep(random.randint(1,5))
        sm.release()
    
    
    if __name__ == '__main__':
        for i in range(20):
            t = Thread(target=task,args=('伞兵%s号'%i,))
            t.start()
    
    
    
    
  • 相关阅读:
    流程控制
    小结
    运算符
    进制之间的转换
    自动类型转换和强制类型转换
    变量
    关键字,标识符,
    NGINX 做TCP转发(端口转发)并记录日志
    redash安装
    解决 es CircuitBreakingException 问题(Data too large Error)
  • 原文地址:https://www.cnblogs.com/king-home/p/10896529.html
Copyright © 2011-2022 走看看