线程,多线程,队列的使用(python操作)

一,线程的实现(线程由计算机本身配置实现)


  1. 什么是进程?进程就是正在运行的程序。进程主要是管理资源的,不是去实现功能的, 包工头:提供资源

  2. 什么是线程?线程时区实现功能的,比如说计算任务,变量的加法运算。线程由操作系统实现 建造者:修房子,建筑的事情就由工人做

  3. 一个进程一定至少有一个线程(一般俗称主线程)

  4. 为什么要写多线程?

    1. 比如我有一件事情,我被要求执行10次,每次时间为2秒
    2. 如果我要用for循环,那我至少要20秒
    3. 开辟多线程,能够快速完成这样的事情
  5. Python通过两个标准库_threadthreading提供对线程的支持,threading_thread进行了封装。threading模块中提供了Thread,Lock,Rlock,Condition等组件。

  6. 多线程的使用方法1

    # 1,生成Thread对象
    import time
    from threading import Thread
    
    def hello(name):
        print('hello,{}'.format(name))
        time.sleep(3)
        print('bye')
    
    def hi():
        print('hi')
        time.sleep(3)
        print('goodbye')
    
    if __name__ == '__main__':
        hello_thread = Thread(target=hello, args=('xyb',), name = '线程2', daemon=True) 
        hi_thread = Thread(target=hi)   # 1.1,创建两个线程对象
        								# 1.2,target参数接收函数对象本身
    									# 1.3,args参数接收值传参到函数里,且只能是元组
                						# 1.4,name参数用来设置线程名字(方法1)
                    					# 1.5, daemon参数用来设置守护线程(方法1)
                    
        hi_thread.setName('线程3')	   # 2.1,setName用来设置线程的名字(方法2)
         
        print(hello_thread.getName())	# 2.2,getName用来获取线程的名字
        print(hi_thread.getName())
            
    	hi_thread.setDaemon(True)		# 3,setDaemon可以设置守护线程,它可以
        					  (方法2# 在主线程结束时也结束该子线程(无join时)		  						     # 必须放在start的前面
         
        
        hello_thread.start()
        hi_thread.start()				# 4,start开始执行线程里的程序
        
        
    
        hello_thread.join()				# 5,join方法会阻塞主线程,等待这两个子
        hi_thread.join()				#	 线程执行完在执行主线程的print任务
       
        print('主线程执行完毕')				
    
  7. 多线程的使用方法2

    import time
    from threading import Thread
    
    
    class MyThread(Thread):
        def __init__(self, people_name, *args, **kwargs):	# 重写__init__方法
            super().__init__(*args, **kwargs)		# 调用父类的__init__方法
            self.people_name = people_name			# 设置改实例的属性
    
        def run(self):
            print('hello, {}'.format(self.people_name))	# 进行传参
            time.sleep(3)
            print('bye')
    
    
    my_thread = MyThread('邢益斌', name='线程2')
    my_thread.start()						# 线程里面调用start就是调用run方法
    print(my_thread.getName())				# 打印出改线程的名字
    

二,线程通信


  1. 在多线程中,所有变量对于所有线程都是共享的,因此,线程之间共享数据最大的危险在于多个线程同时修改一个变量,那就乱套了,所以我们需要互斥锁,来锁住数据。
  2. 线程锁方法1:
  •   2.1,当**没有线程锁**的时候,两个线程访问同一个变量,会起冲突。
    
    # 两个线程在访问同一个变量会起冲突!!
    
    rom threading import Thread
    
    x = 0
    n = 100000
    
    def hello(n):
        global x
        for i in range(n):
            x += 1
    
    def hello1(n):
        global x
        for i in range(n):
            x -= 1
    
    i = Thread(target=hello, args=(n,))
    d = Thread(target=hello1, args=(n,))
    
    i.start()
    d.start()
    i.join()
    d.join()
    
    print(x)
    
    # ---> 输出:
    # 最后x的值不是确定的一个数,两个线程抢变量,不能完整执行每个线程里的代码
    
  •   2.2,当**有线程锁**时,运行速度会变慢,但是会把每个线程里的命令完整执行
    
    from threading import Thread, Lock  # 导入Lock锁模块
    
    x = 0
    n = 100000
    lock = Lock()
    
    
    def hello(n):
        global x
        for i in range(n):
            lock.acquire()	# 线程上锁,其他线程不能访问当前线程使用的变量
            x += 1
            lock.release()	# 线程解锁,变量x可以被其他线程访问
    
    def hello1(n):
        global x
        for i in range(n):
            with lock:		# 第二种方式:使用上下文管理,自动上锁解锁
                a -= 1
    
    i = Thread(target=hello, args=(n,))
    d = Thread(target=hello1, args=(n,))
    
    i.start()
    d.start()
    i.join()
    d.join()
    
    print(x)
    
  1. 线程锁方法2(队列:一个入口,一个出口,先入先出)
  •   3.1通过队列传递数据,安全,不会造成多个线程访问时混乱
    
    from threading import Thread
    from queue import Queue
    from random import randint	# 导入随机数模块
    
    my_queue = Queue(10)    # 参数的含义:当前这个队列最多可存放的元素
    
    def hello(my_queue):
        for i in range(10):
            num = randint(0, 1000)
            my_queue.put(num)	# 在当前my_queue队列中添加10个随机数
            my_queue.join()		# 只要队列里面不为空就会阻塞主程序,不让它运行
    
    def hello1(my_queue):
       A for i in range(5):
            num = my_queue.get()	# 在当前my_queue队列中取出5个数
            my_queue.task_done()	# 每次队列get值之后都跟上,更新底层记计数器
            							empty都是检测计数器来返回TrueFalse
            print(num)				# 打印这5个数
    
    i = Thread(target=hello, args=(my_queue,))
    d = Thread(target=hello1, args=(my_queue,))
    
    i.start()
    d.start()
    i.join()
    d.join()
    print(my_queue.empty())		# 根据实际队列里面的任务返回True False 而不是计数器
    
    # 输出--->
    703
    700
    602
    358
    230
    

三,线程池


  1. 创建线程池类(通过队列实现)

    from threading import Thread  # 导入线程模块
    from queue import Queue  # 导入队列模块
    import time
    
    
    class ThreadPool(object):
        def __init__(self, n):
            self.queue = Queue()  # 设置初始化实例的queue属性为一个队列
            for i in range(n):  # 生成n个线程
                Thread(target=self.worker, daemon=True).start()
         # target传入的是worker方法对象,开启守护线程,并start开始线程运行worker方法
         # n有多少个创建的线程就有多少个
    
        def worker(self):
            while True:  # 从队列里面依次取出put方法放进去的值,运行传入的函数对象本身
                func, args, kwargs = self.queue.get() # 取出一组元组数据,赋值。当队列里面的任务为空时,但是这是一个死循环,取不到值就卡主了,需要守护线程结束掉
                func(*args, **kwargs)	# 执行函数
                self.queue.task_done()  # 刷新底层计数器,以表示这个任务被取出
    
        def put(self, func, args=(), kwargs={}):	
            self.queue.put((func, args, kwargs))	# 在队列中加入一组元组数据
    
        def join(self):
            self.queue.join()  # join作用为根据底层计数器的值来执行是否阻塞队列
    
    
    def hello(name, age):
        print('hello,{},{}岁'.format(name, age))
        time.sleep(2)
        print('bye,{}'.format(age))
    
    
    tp = ThreadPool(10)    # 创建10个线程
    for i in range(10):    # 在队列里面加入10个func, args, kwargs格式的数据
        tp.put(hello, args=(i,), kwargs={'age': i})
    tp.join()				# 根据计数器的值来执行是否阻塞队列,底层计数器为0就不阻塞,不为0就阻塞线程。队列里面的get方法有一个坑,就是如果队列里面的值为0,他还会是去取值,但是会直接阻塞线程!! 只能用守护线程来解决这个坑
    
    """
    手动线程池:
    主要配合队列来进行实现,我们定义好一个队列对象,然后将我们的任务对象put到我们的队列对象中,使用多线程,让我们的线程get队列中的对象,然后各自去执行自己get到的任务
    这样的话其实也就实现了线程池
    
    """
    
  2. Python内置线程池

    from multiprocessing.pool import ThreadPool
    							# 这个内置线程池类似我们上面定义的线程池类
    def hello(name, age):
        print('hello,{},{}岁'.format(name, age))
        time.sleep(2)
        print('bye,{}'.format(age))
    
    
    tp = ThreadPool(5)	# 1 这个内置线程池其实是一个类,这里进行类的实例化,线程数为5
    for i in range(10):
        tp.apply_async(hello, args=(i,), kwds={'age': i})
    											# 把任务提交到内置线程池
         
    tp.terminate()		# 终止线程池,终止所有任务
    tp.close()			# 2.关闭线程池,必须做,停止提交任务到线程池,但不会结束猪吃菜
    tp.join()			# 3.阻塞主线程,等待线程执行任务
    
    """
    	1. 创建线程池.  			线程池:猪圈,线程池中的线程:猪
    	2. 将任务扔进去.  	   任务是白菜
    	3. 关闭线程池.  			停止将任务发送给线程池,也就是停止投送白菜
    	4. 等待线程任务执行完毕.   等待圈中的猪把已经投进去的白菜吃完
    """
    cpu为4核就是4个系统线程,超线程技术:48线程 412线程等等...
    

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值