zoukankan      html  css  js  c++  java
  • 线程的那些事儿

    一、线程的基本概念:

      

      线程被称为轻量级进程。

      计算机的执行单位以线程为单位。计算机的最小可执行是线程。

      进程是资源分配的基本单位。线程是可执行的基本单位,是可被调度的基本单位。

      线程不可以自己独立拥有资源。线程的执行必须依赖所属进程中的资源。

      进程中必须至少有一个线程。

      由于GIL(全局解释锁,只在Cpython中有),导致线程没有真正的并行。

      线程分为用户级线程和内核级线程。

    二、进程由  代码段、数据段、PCB(进程控制块)组成

      线程由  代码块、数据块、TCB(线程控制块)组成

    三、线程和进程的比较

      thread -- 线程

      导入线程模块的两种方法:

      import   threading

      from   threading   import  Thread

      (1) cpu 切换进程比切换线程 慢很多。在python中,如果IO操作过多的话,使用多线程最好了。

      (2) 在同一进程内,所有线程共享这个进程的pid,也就是说所有的线程共享所属进程的资源和内存。

      (3) 在同一个进程内,所有线程共享该进程中的全局变量

      (4) 因为有GIL锁的存在,在Cpython中,没有真正的线程并行。但是有多进程并行

         当任务是计算密集的情况下使用多进程。

      (5) 守护线程和守护进程的区别

         守护进程:要么自己正常结束,要么等主进程的代码结束。

         守护线程:要么自己正常结束,要么要等主进程的进程结束。

    四、线程的使用方法。

      (1)锁机制

          递归锁  Rlock()  可以有无数的锁,但是这些锁有一把万能钥匙。

        

    from threading import Thread, RLock
    
    
    def fn(r_tot, r_pap):
        r_tot.acquire()
        print('我在厕所')
        r_pap.acquire()
        print('我还有纸')
        r_tot.release()
        r_pap.release()
    
    
    def fn1(r_pap, r_tot):
        r_pap.acquire()
        print('wo也有纸')
        r_tot.acquire()
        print('我想上厕所')
        r_pap.release()
        r_tot.release()
    
    
    r_tot = r_pap = RLock()
    t1 = Thread(target=fn, args=(r_tot, r_pap))
    t2 = Thread(target=fn1, args=(r_pap, r_tot))
    t1.start()
    t2.start()
    线程中的递归锁(Rlock)

        

          互斥锁  Lock()  一把锁配一把钥匙

          GIL:全局解释锁  锁的是线程,同一时间只允许一个线程访问cpu

      (2)信号量

          from threading import Semaphore

          

    from threading import Thread, Semaphore
    import time
    
    
    def fn(s, i, color):
        s.acquire()
        print('%s%s个小浣熊出生了33[0m' % (color, i))
        time.sleep(1)
        s.release()
    
    
    def fn1(s, i, color):
        s.acquire()
        print('%s%s个大灰狼来吃小浣熊了33[0m' % (color, i))
        s.release()
    
    
    s = Semaphore(5)
    for i in range(10):
        t1 = Thread(target=fn, args=(s, (i + 1), '33[35m'))
        t2 = Thread(target=fn1, args=(s, (i + 1), '33[36m'))
        t1.start()
        t2.start()
    线程中的信号量(Semaphore)

          

      (3)事件

        from threading import Event

        

    from threading import Thread,Event
    import time,random
    
    def conn_mysql(e,i):
        count = 1
        while count <= 3:
            if e.is_set():
                print('第%s个人连接成功!'%i)
                break
            print('正在尝试第%s次重新连接...'%(count))
            e.wait(0.5)
            count += 1
    
    def check_mysql(e):
        print('33[42m 数据库正在维护 33[0m')
        time.sleep(random.randint(1,2))
        e.set()
    
    
    if __name__ == '__main__':
        e = Event()
        t_check = Thread(target=check_mysql,args=(e,))
        t_check.start()
    
        for i in range(10):
            t_conn = Thread(target=conn_mysql,args=(e,i))
            t_conn.start()
    线程事件机制(Event)

      (4)条件

        from threading import Condition

        条件是让程序员自行去调度线程的一个机制

        Condition 有四个方法

        acquire()

        release()

        wait()  是让线程阻塞

        notify(int)  是指给wait发一个信号,让wait 变成 不阻塞

              int 是指,要给多少个wait 发信号

        

    from threading import Thread,Condition
    def func(con,i):
        con.acquire()
        con.wait()# 线程执行到这里,会阻塞住,等待notify发送信号,来唤醒此线程
        con.release()
        print('第%s个线程开始执行了!'%i)
    
    if __name__ == '__main__':
        con = Condition()
        for i in range(10):
            t = Thread(target=func,args=(con,i))
            t.start()
        while 1:
            num = int(input(">>>"))
            con.acquire()
            con.notify(num)# 发送一个信号给num个正在阻塞在wait的线程,让这些线程正常执行
            con.release()
    使用条件去调度线程

      (5)定时器

        from threading import Timer

        Timer(time, func)

        time:表示睡眠的时间,以秒为单位

        func:睡眠之后需要执行的任务。

        

    from threading import Timer
    
    
    def fn():
        print('我要执行了')
        print(type(te))
    
    
    te = Timer(2, fn)     # 等待2秒,然后执行fn。
    
    te.start()
    定时器(Timer)

    五、线程池

        from concurrent.futures import ThreadPoolExector

        concurrent.futures  这个模块是异步调用的机制

        提交任务的方法有两种:

          t = ThreadPoolExector

          1.  t.submit(func,参数)

          2.  t.map(func,可迭代对象)

        在进程池中用 apply_async() 时,主进程要写close 和 join

        在线程池中 要写shutdown 作用相当于进程池中的 close + join        

        不同的提交任务的方式获取值的方法也不同。

          t.submit()提交,需要用result()来获取

          

          t.map() 提交,需要用__next__来获取

          

    from concurrent.futures import ThreadPoolExecutor
    def fn(num):
        sum = 0
        for i in range(num):
            sum += i
        print(sum)
    t = ThreadPoolExecutor()
    for i in range(10)
        t.submit(fn,i)
    t.shutdown()
    线程池(concurrent.frutures)
    from concurrent.futures import ThreadPoolExecutor
    
    
    def fn(i):
        num = 0
        for el in range(i):
            num += el
        print(num)
    
    
    t = ThreadPoolExecutor(5)
    
    t.map(fn, range(10))
    t.shutdown()
    map实现线程池

        线程池中的回调函数

        线程中的回调函数是由子线程调用的

        

    from concurrent.futures import ThreadPoolExecutor
    import time
    import threading
    
    
    def fn1(num):
        time.sleep(2)
        print('子线程', threading.current_thread())
        return num
    
    
    def fn2(sta):
        time.sleep(2)
        print('回调函数', threading.current_thread())
    
    
    t = ThreadPoolExecutor()
    print('主线程', threading.current_thread())
    time.sleep(2)
    for i in range(2):
        t.submit(fn1, i).add_done_callback(fn2)
    t.shutdown()
    回调函数被谁调用的代码
    from concurrent.futures import ThreadPoolExecutor
    
    
    def fn1(num):
        sum = 0
        for i in range(num):
            sum += i
        return sum
    
    
    def fn2(sta):
        print(sta.result())
    
    
    t = ThreadPoolExecutor()
    for i in range(10):
        t.submit(fn1, i).add_done_callback(fn2)
    t.shutdown()
    线程中的回调函数

      

  • 相关阅读:
    forward和redirect的区别详解
    j2ee部分jar包的作用
    Struts2的工作原理(图解)详解
    struts2的s:iterator 标签 详解
    Struts2 控制标签:<s:if>、<s:elseif>和<s:else>
    Struts2 资源配置文件国际化详解
    ActionContext和ServletActionContext区别以及action访问servlet API的三种方法
    js获取class
    怎么解决eclipse报PermGen space异常的问题
    SQL模糊查找语句详解
  • 原文地址:https://www.cnblogs.com/wf123/p/9525730.html
Copyright © 2011-2022 走看看