zoukankan      html  css  js  c++  java
  • Python3.x基础学习-线程和进程(二)

    进程、线程、协程对比

    进程是操作系统资源分配的单位
    线程是CPU调度的单位
    进程切换需要的资源最大,效率很低
    线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)
    协程切换任务资源小,效率高
    多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发

    同步和异步

    异步:调用在发出之后,这个调用就直接返回,不管有无结果:异步是过程
    非阻塞:关注的是程序在等待调用结果(消息,返回值)时的状态,指在不能立刻得到结果之前,该调用不会阻塞当前线程

    同步异步的区别
    同步:一个服务的完成需要依赖其他服务时,只有等待被依赖的服务完成后,才算完成,这是一种可靠的服务序列。要么成功都成功,要么失败都失败,
    服务的状态可以保持一致
    异步:一个服务的完成需要依赖其他服务时,只通知其他依赖服务开始执行,而不需要等待被依赖的服务完成,此时该服务就算完成了。被依赖的服务是
    否最终完成无法确定,因此他是一个不可靠的服务序列

    消息通知中的同步和异步:
    同步:当一个同步调用发出后,调用者一直等待返回消息(或者调用结果)通知后,才能进行后续的执行
    异步:当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。在调用结束之后,通过消息回调来通知调用者是否调用成功。

    阻塞和非阻塞区别:
    阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务,函数只有在得到结果之后,才会返回
    非阻塞:非阻塞和阻塞的结果相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

    同步与异步是对应的,他们是线程之间的关系,两个线程之间要么是同步的,要么是异步的

    阻塞与非阻塞是同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。

    阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果

    守护线程

    setDaemon() 将当前线程设置成守护线程来守护主线程:-当主线程结束后,守护线程也就结束,不管是否执行完成
    -应用场景:qq多个聊天窗口,就是守护线程
    注意:需要在子线程开启的时候设置成守护线程,否则无效

    import time,threading
    
    def dance():
        for i in range(3):
            time.sleep(0.5)
            print("正在跳舞")
    def sing():
        for i in range(3):
            time.sleep(0.8)
            print('正在唱歌')
    
    t1 = threading.Thread(target=dance)
    t2 = threading.Thread(target=sing)
    
    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    time.sleep(1)
    print("时间结束。ending")
    
    # 正在跳舞
    # 正在唱歌
    # 时间结束。ending
    # ------run------- 0
    # ------run------- 1
    # ------run------- 2
    # 正在跳舞

    -getName() 获取线程的名称
    -setName() 设置线程的名称
    -isAlive() 判断当前线程存活状态

    import time,threading
    
    def dance():
        for i in range(3):
            time.sleep(0.8)
            print('正在跳舞')
    
    def sing():
        for i in range(3):
            time.sleep(0.8)
            print("正在唱歌")
    
    t1 = threading.Thread(target=dance)
    t2 = threading.Thread(target=sing)
    t1.setName('线程1')
    # t2.setName('线程2')
    print(t1.is_alive())
    t1.start()
    print(t1.is_alive())
    t2.start()
    print(t1.getName())
    print(t2.getName())
    
    # False
    # True
    # 线程1
    # Thread-2
    # ------run------- 0
    # ------run------- 1
    # ------run------- 2
    # 正在跳舞
    # 正在唱歌
    # 正在唱歌
    # 正在跳舞
    # 正在唱歌
    # 正在跳舞

    threading.currentThread():返回当前的线程变量
    threading.enumrate(): 返回一个包含正在运行的线程list,正在运行线程启动后、结束前,不包括启动前和终止后的线程。
    threading.activeCount():返回正在运行的线程数量,与len(threading.enumrate())有相同的结果
    import threading,time
    
    def dance():
        print('dance',threading.current_thread())
        for i in range(3):
            time.sleep(0.5)
            print('正在跳舞')
    def sing():
        print('sing',threading.current_thread())
        for i in range(3):
            time.sleep(0.5)
            print('正在唱歌')
    
    t1 = threading.Thread(target=dance)
    t2 = threading.Thread(target=sing)
    
    print(threading.current_thread())
    # print(threading.enumerate())
    t1.start()
    t2.start()
    
    print('启动后的线程列表-->',threading.enumerate())
    print(threading.active_count())
    print(len(threading.enumerate()))
    
    # <_MainThread(MainThread, started 1536)>
    # dance <Thread(Thread-1, started 2000)>
    # sing <Thread(Thread-2, started 10484)>
    # 启动后的线程列表--> [<_MainThread(MainThread, started 1536)>, <Thread(Thread-1, started 2000)>, <Thread(Thread-2, started 10484)>]
    # 3
    # 3
    # 正在唱歌
    # 正在跳舞
    # 正在唱歌
    # 正在跳舞
    # 正在唱歌
    # 正在跳舞
    from threading import Thread
    
    class MyThread(Thread):
        def __init__(self,num):
            super(MyThread,self).__init__()
            self.num =num
        def run(self):
            for i in range(self.num):
                print('------run-------',i)
    
    if __name__ == '__main__':
        my = MyThread(3)
        my.start()
        
    # ------run------- 0
    # ------run------- 1
    # ------run------- 2
    多线程开发的时候共享全局变量会带来资源竞争
    # 多线程开发的时候共享全局变量会带来资源竞争的效果,也就是数据不安全
    
    import threading,time
    g_num = 0
    
    def func1(n):
        global g_num
        for i in range(n):
            time.sleep(0.01)
            g_num+=1
        print('--func1---',g_num)
    
    def func2(n):
        global g_num
        for i in range(n):
            time.sleep(0.01)
            g_num+=1
        print('--func2--',g_num)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=func1,args=(10000,))
        t2 = threading.Thread(target=func2,args=(10000,))
        t1.start()
    线程锁

    from threading import Thread,Lock
    
    # 互斥锁
    lock = Lock()  # 创建锁
    lock.acquire() # 加锁
    lock.release() # 释放锁
    
    g_num = 0
    
    def func1(n):
        global g_num
        for i in range(n):
            lock.acquire()
            g_num+=1
            lock.release()
        print('--in func1--',g_num)
    def func2(n):
        global g_num
        for i in range(n):
            lock.acquire()
            g_num+=1
            lock.release()
        print('--in func2--',g_num)
    
    if __name__ =='__main__':
        lock = Lock()
        t1 = Thread(target=func1,args=(10000,))
        t2 = Thread(target=func2,args=(10000,))
        t1.start()
        t2.start()
    
    # --in func1-- 10000
    # --in func2-- 20000


    # 在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁现象
    # 如果锁之间相互嵌套,就有可能出现死锁。因此尽量不要出现锁之间的嵌套
    
    import threading,time
    printer_lock = threading.Lock() # 创建打印机锁
    paper_lock =threading.Lock()   #简历锁
    
    class Printer(threading.Thread):
        def run(self):
            print('--printer start--')
            paper_lock.acquire()
            time.sleep(1)
            print("编写简历1")
            printer_lock.acquire()
            print("正在使用打印机1")
            printer_lock.release()
            paper_lock.release()
            print("printer end")
    
    class Paper(threading.Thread):
        def run(self):
            print("---paper start--")
            printer_lock.acquire()
            time.sleep(1)
            print('编写简历2')
            paper_lock.acquire()
            print("正在使用打印机2")
            printer_lock.release()
            paper_lock.release()
            print('paper end')
    
    if __name__ == '__main__':
        printer = Printer()
        paper = Paper()
        printer.start()
        paper.start()
        
    # --printer start--
    # ---paper start--
    # 编写简历2
    # 编写简历1
    # 一个threadLocal 变量虽然是全局变量,但是每个线程都只能读写自己线程的独立副本,互不干扰。
    # threadLocal 解决了参数在一个线程中各个函数之间相互传递的问题
    
    import threading
    local = threading.local()
    
    def func1():
        print(local.num)
    
    
    def func2():
        local.num = 5
        local.num+=10
        print(threading.current_thread())
        func1()
    
    t1 = threading.Thread(target=func2)
    t1.start()
    
    # <Thread(Thread-1, started 3284)>
    # 15

    线程和进程的对比

    from multiprocessing import Process
    
    import time
    
    def func1():
        start = time.time()
        i = 0
        for i in range(20000000):
            i +=1
    
        end = time.time()
        print("func1--total_time:",end-start)
    
    
    def func2():
        start = time.time()
        i = 0
        for i in range(20000000):
            i += 1
    
        end = time.time()
        print("func2--total_time:", end - start)
    
    if __name__ == '__main__':
        p1 = Process(target=func1)
        p2 = Process(target=func2)
        p1.start()
        p2.start()
    
    # func2--total_time: 1.0018956661224365
    # func1--total_time: 1.0268356800079346
    
    import threading
    import time
    
    def func1():
        start = time.time()
        i = 0
        for i in range(20000000):
            i +=1
    
        end = time.time()
        print("func1--total_time:",end-start)
    
    
    def func2():
        start = time.time()
        i = 0
        for i in range(20000000):
            i += 1
    
        end = time.time()
        print("func2--total_time:", end - start)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=func1)
        t2 = threading.Thread(target=func2)
        t1.start()
        t2.start()
        # func1 - -total_time: 1.7554385662078857
        # func2 - -total_time: 1.8083033561706543
    
    
    import time
    num =0
    start =time.time()
    for i in range(20000000):
        i+=1
    end = time.time()
    
    print(end-start)   #3.700019598007202

    协程

    # 协程切换一百万次
    
    import time
    
    def func1():
        start = time.time()
        for i in range(1000000):
            yield
        end = time.time()
        print("in func1 total_time:",end-start)
    
    def func2(g):
        start = time.time()
        for i in range(1000000):
            g.__next__()
        end = time.time()
        print('in func2 total_time:',end-start)
    
    g = func1()
    func2(g)
    # in func2 total_time: 0.11689877510070801

    生产者模式和消费者模式

    q = queue.Queue(3) 3表示只能存放3个数据
    参数:maxsize 是队列中允许的最大项数。如果省略此参数,则无大小限制。返回值q是队列对象
    2.put()方法,向队列中存放数据。如果队列已满,此方法阻塞直至有空间可用为止。
    3.get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止
    4.get_nowait():不等待,直到抛出异常
    5.full()如果q已满,返回为True
    6.q.empty()如果调用此方法时q为空,返回为True
    7.qsize()获取队列中数据的个数
    import queue
    
    q = queue.Queue(2)
    q.put("hello")
    q.put("world")
    print(q.full())
    print(q.qsize())
    print(q.get())
    print(q.get())
    
    # True
    # 2
    # hello
    # world


    import queue
    import threading
    import time
    list = []
    def produce(name):
    for i in range(1,11):
    print("%s生产了包子%d"%(name,i))
    q.put(i)
    time.sleep(0.5)

    def custom(name):
    while True:
    print("%s吃了包子%d"%(name,q.get(timeout=10)))



    if __name__ =='__main__':
    q = queue.Queue()
    t1 = threading.Thread(target=produce,args=('johnson',))
    t2 = threading.Thread(target=custom,args=('may',))
    t1.start()
    t2.start()

    # johnson生产了包子1
    # may吃了包子1
    # johnson生产了包子2
    # may吃了包子2
    # johnson生产了包子3
    # may吃了包子3
    # johnson生产了包子4
    # may吃了包子4
    # johnson生产了包子5
    # may吃了包子5
    # johnson生产了包子6
    # may吃了包子6
    # johnson生产了包子7
    # may吃了包子7
    # johnson生产了包子8
    # may吃了包子8
    # johnson生产了包子9
    # may吃了包子9
    # johnson生产了包子10
    # may吃了包子10
     

    练习

    """
    创建两个进程:进程A和进程B,用jcq消息队列实现他们的通信。
    1、进程A里创建两个线程:线程A1 、线程A2.
    在进程A1里创建一个a列表 [1,2,3,4,5,6], 线程A1用消息队列将列表传递给线程A2,线程A2.
    对列表进行筛选,删除掉奇数。然后用进程jcq消息队列发送给进程B
    2、在进程B里创建两个线程:线程B1、线程B2
    线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1
    线程B1求出所有数的和并打印结果
    """
    from multiprocessing import Process,Queue
    from threading import Thread
    import queue
    def JcA(Q):
        qa = queue.Queue()
        a=[1, 2, 3, 4, 5, 6]
        xca1 = Thread(target=XcA1,args=(qa,a))
        xca2 = Thread(target=XcA2,args=(qa,Q))
        xca1.start()
        xca1.join()
        xca2.start()
        xca2.join()
    def XcA1(qa,lst):
        for i in lst:
            qa.put(i)
    def XcA2(qa,Q):
        for i in range(qa.qsize()):
            num = qa.get()
            if num%2==0:
                pass #放到进程消息队列中
                Q.put(num)
    # 2、在进程B里创建两个线程:线程B1、线程B2
    # 线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1
    # 线程B1求出所有数的和并打印结果
    def JcB(Q):
        qb = queue.Queue()
        xcb1 = Thread(target=XcB1, args=(qb,))
        xcb2 = Thread(target=XcB2, args=(Q,qb))
        xcb2.start()
        xcb2.join()
        xcb1.start()
        xcb1.join()
    def XcB1(qb):
       # pass  #从线程消息队列中取数据,求出所有数的和并打印结果
        sum = 0
        for i in range(qb.qsize()):
            sum+=qb.get()
        print(sum)
    def XcB2(Q,qb):
        # pass#从进程队列中取数据,用线程消息队列传递给B1
        for i in range(Q.qsize()):
            qb.put(Q.get())
    if __name__ == '__main__':
        Q = Queue()
        pa = Process(target=JcA,args=(Q,))
        pb = Process(target=JcB,args=(Q,))
        pa.start()
        pa.join()
        pb.start()
  • 相关阅读:
    jquery 源码学习(二)
    附加作业2
    附加题1
    实验八:一维数组的应用
    第七次作业总结
    第七次作业
    实验六:函数
    Thanks for your encourage!
    实验五:循环结构
    作业四 分支结构
  • 原文地址:https://www.cnblogs.com/johnsonbug/p/12710036.html
Copyright © 2011-2022 走看看