zoukankan      html  css  js  c++  java
  • 线程

    1.queue队列

    2.进程间通讯IPC机制

    3.什么是线程(理论)

    4.开启线程的俩种方式

    5.生产者消费者模型

    6.线程的其他方法

    7.线程间是可以通讯的

    8.守护线程

    9.互斥锁

    一.queue队列

     1.队列:先进先出

     2.堆栈:先进后出

     1 # get和put最好是一一对应,而且不要超过你传入的最大值,不会回进入阻塞态
     2 from multiprocessing import Queue
     3 
     4 q = Queue(5)# 括号内可以放参数,表示的是这个队列最大存储量
     5 
     6 q.put('q')
     7 q.put('w')
     8 q.put('e')
     9 q.put('r')
    10 q.put('t')
    11 q.put('t')# 如果队列被放满了,还继续往队列里面添加值,程序不会报错,会原地等待,直到有人取走值
    12 
    13 
    14 print(q.get())
    15 print(q.get())
    16 print(q.get())
    17 print(q.get())
    18 print(q.get())# 如果没有值取空了,在取的话,程序会进入阻塞状态,知道有人继续往队列中添加值
    19 
    20 
    21 '''
    22 还有几种方法(但这几种方法都不适用多进程的情况)
    23 q.full()判断队列是否满了
    24 print(q.empty())判断队列中的数据数据是否取完了
    25 print(q.get_nowait())取值,没有值不等待直接报错
    26 '''
    View Code
     

    二.进程间通讯IPC机制

    进程间通讯
    ​通讯指的就是交换数据
    进程之间内存是相互隔离的,当一个进程想要把数据给另外一个进程,就需要考虑IPC
    用队列可以测验出进程间是可以通过一些方法进行通讯的
    from multiprocessing import Process,Queue
    
    def qwe(q):
        q.put('hello ')
    
    
    def zxc(q):
        print(q.get(q))
    
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=qwe,args=(q,))
        p1 = Process(target=zxc,args=(q,))
        p.start()
        p1.start()


    三.什么是线程

    什么是线程:
        线程是操作系统最小的运算调度单位,被包含在进程中,一个线程就是一个固定的执行流程
    
    线程和进程的关系:
        线程不能单独存在,必须存在于进程中,
    进程是一个资源单位,其中包含了运行程序所需要的所有资源
    
        线程才是真正的执行单位,没有线程,进程中的资源无法被利用起来,
    所以一个进程至少包含一个线程,称之为主线程,当我们启动一个程序时,
    操作系统就会自己为这个程序创建一个主线程,线程也可以由程序后期开启,
    自己开启的线程称之为子线程
    
    
    那位什么需要线程:
        开进程:
            1 申请内存空间 ,耗资源
            2 拷贝代码 ,耗资源
    
        开线程:
            目的只有一个就是提高效率,将内存比如工厂,那么进程就相当于是工厂里面的车间,
            而你的线程就相当于是车间里面的流水线,要是生产量跟不上的话,你肯定是创建新的流水线,
            而不是创建一个新的工厂
    
        一个进程内可以起多个线程,并且线程与线程之间的数据是共享的
        ps:开启线程的开销要远远小于开启进程的开销
    
    
    

    四.开启线程的俩种方式

    创建线程的俩种方式
    跟创建进程的方式是一样的

    一》

    from threading import Thread
    import time
    
    def task(name):
        print('%s is running'%name)
        time.sleep(2)
        print('%s is over'%name)
    # 注意:开启线程的时候不需要在__main__内
    t = Thread(target=task,args=('zy',))
    t.start()# 告诉操作系统开一个线程,线程的开销远远小于进程
    # 小到代码一执行完,线程就开启了
    print('主')

    二》

    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'%self.name)
            time.sleep(2)
            print('%s is over'%self.name)
    
    t = MyThread('zy')
    t.start()
    print('主')

    五.生产者消费者模型

    生产者消费者是什么:

    生产者消费者
    生产者消费者模型是什么:
    模型,就是解决摸个问题的套路,
    产生数据的一方称之为生产者,
    处理数据的一方称之为消费者,
    列如:爬虫,生活中到处都是这种模型,
    饭店 厨师即使生产者,你吃饭的人就是消费者
    
    ## 生产者和消费者出啥问题了?   解决什么问题
    ​    生产者和消费,处理速度不平衡,一方快一方慢,导致一方需要等待另一方
    ## 生产者消费者模型解决这个问题的思路:     怎么解决
    ​    原本,双方是耦合 在一起,消费必须等待生产者生成完毕在开始处理, 反过来
    ​    如果消费消费速度太慢,生产者必须等待其处理完毕才能开始生成下一个数据
    
    ### 解决的方案:
    ​    将双方分开来.一专门负责生成,一方专门负责处理
    ​    这样一来数据就不能直接交互了 双方需要一个共同的容器
    ​    生产者完成后放入容器,消费者从容器中取出数据
    ​    这样就解决了双发能力不平衡的问题,做的快的一方可以继续做,不需要等待另一方

    列子:

    生产者:生产/制造数据的
    消费者:消费/处理数据的
    例子:做包子的,买包子的
    1.做包子远比买包子的多
    2.做包子的远比买包子的少
    如何解决供需不平衡的问题

    第一种解决方法:
     1 第一个版本
     2 from multiprocessing import Process,Queue,JoinableQueue
     3 import random
     4 import time
     5 
     6 
     7 def zuo(name,food,q):
     8     for i in range(10):
     9         data = '%s 生产了%s%s'%(name,food,i)
    10         time.sleep(random.random())
    11         q.put(data)
    12         print(data)
    13 
    14 def chi(name,q):
    15     while True:
    16         data = q.get()
    17         if data == None:break# 判断取到的是否为空
    18         print('%s吃了%s'%(name,data))
    19         time.sleep(random.random())
    20 
    21 if __name__ == '__main__':
    22     q = Queue()
    23     z = Process(target=zuo,args=('厨师zy','牛排',q))
    24     z1 = Process(target=zuo,args=('厨师xj','鸡排',q))
    25     c = Process(target=chi,args=('',q))
    26     c1 = Process(target=chi,args=('动物',q))
    27     z.start()
    28     z1.start()
    29     c.start()
    30     c1.start()
    31     z.join()
    32     z1.join()# 没有这个的话,直接取空,消费者就结束了,确保生产者确确实实生产完了
    33     q.put(None) # 存进去一个None,只要消费者取值得时候取到空了,就带表生产的都被吃完了,然后结束程序
    34     q.put(None)
    35 
    36 第一种方法的缺陷:没多一个人我就要多写一个None,要是人有成千上万怎么办
    View Code

    第二种方法:用JoinableQueue方法解决

    JoinableQueue里面的方法:

    JoinableQueue

    可以被join的队列

    join是等待任务结束

    队列怎么叫结束?

    调用task_done一次则表示有一个数据被处理完成了 当task_done次数等于put的次数就意味着任务处理完成了

    这也是join的执行时机

    该队列可以明确告知数据的使用方,所有数据都已经处理完成

    在生产者消费者模型中,解决了消费者不知道何时算是任务结束的问题

    具体过程:主进程先等待所有的生产者进程生成完毕,再等队列中的数据被全部处理,这就意味着,任务全部结束

     1 from multiprocessing import Process,JoinableQueue
     2 import random
     3 import time
     4 
     5 
     6 def zuo(name,food,q):
     7     for i in range(10):
     8         data = '%s 生产了%s%s'%(name,food,i)
     9         time.sleep(random.random())
    10         q.put(data)
    11         print(data)
    12 
    13 def chi(name,q):
    14     while True:
    15         data = q.get()
    16         print('%s吃了%s'%(name,data))
    17         time.sleep(random.random())
    18         q.task_done()# 告诉队列你已经从队列中取出了一个数据,并且处理完毕
    19 
    20 if __name__ == '__main__':
    21     q = JoinableQueue()
    22     z = Process(target=zuo,args=('厨师zy','牛排',q))
    23     z1 = Process(target=zuo,args=('厨师xj','鸡排',q))
    24     c = Process(target=chi,args=('',q))
    25     c1 = Process(target=chi,args=('动物',q))
    26     z.start()
    27     z1.start()
    28     c.daemon = True# 将消费者设为守护进程,主线程结束,子线程也就结束了
    29     c1.daemon = True
    30     c.start()
    31     c1.start()
    32     z.join()# 确保生产者确确实实生产完了
    33     z1.join()
    34 
    35     q.join()# 等待队列中数据全部取出
    View Code

    六.线程的其他方法

    from threading import Thread,current_thread,active_count
    import time
    import os
    
    def task(name,i):
        print('%s is running'%name)
        # print('子current_thread:',current_thread().name)# 查看子线程
        # print('子',os.getpid())
        time.sleep(i)
    
        print('%s is over'%name)
    # 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
    t = Thread(target=task,args=('egon',1))
    t1 = Thread(target=task,args=('jason',2))
    t.start()  # 告诉操作系统开辟一个线程  线程的开销远远小于进程
    t1.start()  # 告诉操作系统开辟一个线程  线程的开销远远小于进程
    t1.join()  # 主线程等待子线程运行完毕
    print('当前正在活跃的线程数',active_count())# 查看正在活跃的线程数
    # 小的代码执行完 线程就已经开启了
    print('')
    # print('主current_thread:',current_thread().name)
    # print('主',os.getpid())# 查看线程id

    七.线程间是可以通讯的

    from threading import Thread
    
    money = 666
    
    def task():
        global money
        money = 999
    
    t = Thread(target=task)
    t.start()
    t.join()
    print(money)
    
     线程之间是可以通信的,数据之间不是相互隔离的
    结果是999

    八.守护线程

    一个线程可以设置为另一个线程的守护进程
    特点:被守护线程结束后守护线程也随之结束
    
    守护线程会等到所有非守护线程结束后结束!前提是除了主线程之外,还有其他的非守护线程
    当然如果守护线程已经完成任务,就会立马结束
     1 from threading import Thread
     2 import time
     3 
     4 def task():
     5     print("子1running......")
     6     time.sleep(5)
     7     print("子1over......")
     8 
     9 def task2():
    10     print("子2running......")
    11     time.sleep(4)
    12     print("子2over......")
    13 
    14 t = Thread(target=task)
    15 t.daemon = True
    16 t.start()
    17 
    18 t2 = Thread(target=task2)
    19 t2.start()
    20 print("主over")
    View Code

    九.互斥锁

    线程互斥锁
    不管是进程还是线程,只要共享就意味着竞争,线程中也存在安全问题,
    多线程可以并发执行,一旦并发了并且访问了同一个资源就会出现问题,
    解决方案:还是要加互斥锁
     1 from threading import Thread,Lock
     2 import time
     3 
     4 n = 100
     5 
     6 def task(mutex):
     7     global  n
     8     mutex.acquire()
     9     tmp = n
    10     time.sleep(0.1)
    11     n = tmp - 1
    12     mutex.release()
    13 
    14 t_list = []
    15 mutex = Lock()
    16 for i in range(100):
    17     t = Thread(target=task,args=(mutex,))
    18     t.start()
    19     t_list.append(t)
    20 for t in t_list:
    21     t.join()
    22 print(n)
    23 
    24 开100个线程,每一次都去减一,最终打印结果为0,如果不加锁的话打印结果为99,因为每个线程拿到的都是100,100减1等于99
    View Code
  • 相关阅读:
    sfs2x 连接 mongodb
    java websocket
    webstorm 4.0 注册码
    解决 sfs2 admin tool 找不到扩展
    window 注册表五大类
    opengl 学习第二日
    java google Protobuf
    扩展 java sencha touch PhonegapPlugin
    sencha touch2 kryonet socket phonegap 通信 作者:围城
    sencha touch2 layout 笔记
  • 原文地址:https://www.cnblogs.com/zahngyu/p/11342197.html
Copyright © 2011-2022 走看看