• 网络编程------线程相关问题.


    线程与进程的区别:

    1. 计算机的执行单位: 线程.    计算机的最小可执行是线程
    2. 进程是资源分配的基本单位, 线程是可执行的基恩单位, 是可被调度的基本单位.
    3. 线程不可以自己独立的拥有资源, 线程的执行, 必须依赖于所属进程中的资源.
    4. 线程被称为轻量级的进程.
    5. 进程中必须至少有一个线程

    注意: 在pychon中  算法类的运算变成 使用进程会更好.   

         因为pychon中有个GIL:全局解释锁(只有C语言编写的pychon解释器才有.(Cpychon))

      对于线程来说, 因为有了GIL, 所以没有真正的并发.

    线程有分为用户级线程和内核级线程.(了解)

      用户级线程: 对于程序猿 来说的, 这样的线程完全被程序员控制执行, 调度.

      内核级线程: 对于计算机内核来说的, 这样的线程完全被内核控制调度, 不受程序猿调度.

    线程和进程的比较:

      thread - 线程
      import thread 操作线程的模块
      import threading 用这个去操作线程
      (1) cpu切换进程要比cpu切换线程 慢很多
           在python中,如果IO操作过多的话,使用多线程最好了
      (2) 在同一个进程内,所有线程共享这个进程的pid,也就是说所有线程共享所属进程的所有资

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

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

                当你的任务是计算密集的情况下,使用多进程好
          总结:在CPython中,IO密集用多线程,计算密集用多进程

          (5)关于守护线程和守护进程的事情(注意:代码执行结束并不代表程序结束)
              守护进程:要么自己正常结束,要么根据父进程的代码执行结束而结束
              守护线程:要么自己正常结束,要么根据父线程的执行结束而结束

    初识线程:

    进程由 代码段 数据段 PCB组成(process control block  进程控制块)
    线程由 代码段 数据段 TCB组成(thread control block  线程控制块)

    # 函数开启线程方法: 

    1
    # import threading # 导入模块的方法一 2 from threading import Thread # 导入线程函数的方法二 3 4 5 def func(i): # 定义一个子线程 6 print(i) 7 8 9 10 if __name__ == '__main__': 11 for i in range(200): 12 q = Thread(target=func,args=(i,)) # 13 q.start()
    1 # 类方法开启线程的方法:
    2 # class MyThread(Thread): # 实例化一个类. 将线程模块设置为形参.
    3 #     def __init__(self):  # 初始化线程
    4 #         super(MyThread, self).__init__()
    5 #     def run(self):
    6 #         print('我是一个子线程')
    7 #
    8 # t = MyThread()
    9 # t.start()

    线程与进程的对比01:

    from multiprocessing import Process
    from threading import Thread
    import time
    
    
    
    def func():
        pass
    
    if __name__ == '__main__':
        start = time.time()
        for i in range(1000):
            p = Process(target=func)
            p.start()
        print('开100个进程的时间:',time.time() - start)
    
        start = time.time()
        for i in range(1000):
            p = Thread(target=func)
            p.start()
        print('开100个线程的时间:', time.time() - start)

    # 得到的结果线程所用时间远远小于进程时间. 从而判断线程切换CPU的速度远远大于进程.
    # 在python 中, 如果IO操作过多的时候, 使用多线程.

    线程与进程的对比02

     1 from multiprocessing import Process
     2 from threading import Thread
     3 import time,os
     4 
     5 
     6 
     7 def func(name):
     8     print('我是一个%s,我的pid是%s'%(name,os.getpid()))
     9 
    10 
    11 if __name__ == '__main__':
    12 
    13     print('我是main,我的pid是%s'%(os.getpid()))
    14     for i in range(10):
    15         p = Process(target=func,args=('进程',))
    16         p.start()
    17 
    18     for i in range(10):
    19         p = Thread(target=func,args=('线程',))
    20         p.start()

    # 在一个进程中, 所有的线程都共享这个进程的pid号,
    # 也就是说所有的线程都共享这个进程的所有资源和内存地址.

    线程与进程的对比03:

    多进程时候也同样共享所属进程中的全局变量(所有资源和内存地址)

    from multiprocessing import Process
    from threading import Thread,Lock
    import time,os
    
    def func(): 定义一个func线程.
        global num 获得全局变量的num.
        tmp = num
        time.sleep(0.1)
    # 此时每条线程都会睡眠0.1秒(全局解释锁允许线程的反应最大速度为5毫秒),
    # 后被T出CPU, 线程会继续执行,到最后得到的结果为相同的都为99 num
    = tmp - if __name__ == '__main__': num = 100 t_l = [] for i in range(100): t = Thread(target=func) t.start() t_l.append(t) # time.sleep(1) [t.join() for t in t_l] print(num)

    线程三种被迫放弃CPU的过程:

    2线程的使用方法
    (1)锁机制
    递归锁
    RLock() 可以有无止尽的锁,但是会有一把万能钥匙
    互斥锁:
    Lock() 一把钥匙配一把锁
    GIL:全局解释器锁
    锁的是线程,是CPython解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访问cpu
    (2) 信号量:
    from threading import Semaphore
    去看多进程的信号量

    (3) 事件
    from threading import Event
    去看多进程的事件机制

    (4) 条件
    from threading import Condition
    条件是让程序员自行去调度线程的一个机制
    # Condition涉及4个方法
    # acquire()
    # release()
    # wait() 是指让线程阻塞住
    # notify(int) 是指给wait发一个信号,让wait变成不阻塞
    # int是指,你要给多少给wait发信号

    (5) 定时器
    from threading import Timer
    # Timer(time,func)
    # time:睡眠的时间,以秒为单位
    # func:睡眠时间之后,需要执行的任务

    互斥锁:

    1 from multiprocessing import Process
    2 from threading import Thread,Lock
    3 import time,os
    4 
    5 # l = Lock()# 一把钥匙配一把锁
    6 # l.acquire()
    7 # print('abc')
    8 # l.acquire()# 程序会阻塞住   陷入死锁了
    9 # print(123)

     死锁示例:

     1 from multiprocessing import Process
     2 from threading import Thread,Lock
     3 import time,os
     4 
     5 
     6 
     7 def man(l_tot,l_pap):
     8     l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
     9     print('alex在厕所上厕所')
    10     time.sleep(1)
    11     l_pap.acquire()# 男的拿纸资源
    12     print('alex拿到卫生纸了!')
    13     time.sleep(0.5)
    14     print('alex完事了!')
    15     l_pap.release()# 男的先还纸
    16     l_tot.release()# 男的还厕所
    17 
    18 def woman(l_tot,l_pap):
    19     l_pap.acquire()  # 女的拿纸资源
    20     print('小雪拿到卫生纸了!')
    21     time.sleep(1)
    22     l_tot.acquire()  # 是女的获得厕所资源,把厕所锁上了
    23     print('小雪在厕所上厕所')
    24     time.sleep(0.5)
    25     print('小雪完事了!')
    26     l_tot.release()  # 女的还厕所
    27     l_pap.release()  # 女的先还纸
    28 
    29 
    30 if __name__ == '__main__':
    31     l_tot = Lock()
    32     l_pap = Lock()
    33     t_man = Thread(target=man,args=(l_tot,l_pap))
    34     t_woman = Thread(target=woman,args=(l_tot,l_pap))
    35     t_man.start()
    36     t_woman.start()

    死锁解决方法:(配一把公共钥匙)

     1 from multiprocessing import Process
     2 from threading import Thread,RLock
     3 import time,os
     4 # RLock是递归锁 --- 是无止尽的锁,但是所有锁都有一个共同的钥匙
     5 # 想解决死锁,配一把公共的钥匙就可以了。
     6 
     7 def man(l_tot,l_pap):
     8     l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了
     9     print('alex在厕所上厕所')
    10     time.sleep(1)
    11     l_pap.acquire()# 男的拿纸资源
    12     print('alex拿到卫生纸了!')
    13     time.sleep(0.5)
    14     print('alex完事了!')
    15     l_pap.release()# 男的先还纸
    16     l_tot.release()# 男的还厕所
    17 
    18 def woman(l_tot,l_pap):
    19     l_pap.acquire()  # 女的拿纸资源
    20     print('小雪拿到卫生纸了!')
    21     time.sleep(1)
    22     l_tot.acquire()  # 是女的获得厕所资源,把厕所锁上了
    23     print('小雪在厕所上厕所')
    24     time.sleep(0.5)
    25     print('小雪完事了!')
    26     l_tot.release()  # 女的还厕所
    27     l_pap.release()  # 女的先还纸
    28 
    29 
    30 if __name__ == '__main__':
    31     l_tot = l_pap = RLock() # 将Lock 换成RLock就可以解开死锁.
    32     t_man = Thread(target=man,args=(l_tot,l_pap))
    33     t_woman = Thread(target=woman,args=(l_tot,l_pap))
    34     t_man.start()
    35     t_woman.start()

    # 而'万能钥匙'只有一把, 所以只能一次运行结束一个线程, 才能去解决另一个线程, 是另一个线程也结束.

    递归锁:

    递归锁
    RLock() 可以有无止尽的锁,但是会有一把万能钥匙

     1 from threading import RLock
     2 
     3 s = RLock()
     4 s1 = RLock()
     5 s.acquire()
     6 s.acquire()
     7 s.acquire()
     8 s.acquire()
     9 s.acquire()
    10 s.acquire()
    11 print(123)

    # 可以有无止境的锁.但是只有一把万能钥匙, 所以一次只能结束一条线程.

    #  注意:

      万能钥匙(递归锁  RLock()  )  和互斥锁(  Lock()  )   要根据实际情况来使用!!!  

      而在变成中一定要细心, 可以多用print()去一步一步实现.

    锁机制
    递归锁
    RLock() 可以有无止尽的锁,但是会有一把万能钥匙
    互斥锁:
    Lock() 一把钥匙配一把锁
    GIL:全局解释器锁
    锁的是线程,是CPython解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访


    信号量相关:

    from threading import Semaphore
    与多进程的信号量类似

    from threading import Semaphore,Thread
    import time
    
    
    def func(sem,i):
        sem.acquire() # 拿钥匙锁门
        print('第%s个人进入屋子'%i)
        time.sleep(2)
        print('第%s个人离开屋子'%i)
        sem.release() # 还钥匙开门

    # if __name__ == '__main__':  # 在线程代码中, 可有可无, pycham解释器会自动补齐(其他解释器还没实践.)
    sem = Semaphore(5) # 相当于5把钥匙1把锁, 一次可以进去5个人.
    for i in range(20): # 定义20个人
        t = Thread(target=func,args=(sem,i))
        t.start()

    事件: ( Event() )

    from threading import Event
    与多进程的事件机制类似

     1 from threading import Thread,Event
     2 import time,random
     3 
     4 def conn_mysql(e,i):
     5     count = 1
     6     while count <= 3:
     7         if e.is_set():
     8             print('第%s个人连接成功!'%i)
     9             break
    10         print('正在尝试第%s次重新连接...'%(count))
    11         e.wait(0.5)
    12         count += 1
    13 
    14 def check_mysql(e):
    15     print('33[42m 数据库正在维护 33[0m')
    16     time.sleep(random.randint(1,2)) 
    # 连接服务器是否成功受此行代码影响, 如果睡1秒的话, conn_mysql 函数中尝试两次(即循环两次就够1秒,) 从而能够登陆成功.
    # 如果睡眠时间是2秒, conn_mysql三次循环以后,函数会结束, 传输的登陆请求会接收不到,从而登陆不成功.
    17 e.set() 18 19 20 if __name__ == '__main__': 21 e = Event() 22 t_check = Thread(target=check_mysql,args=(e,)) 23 t_check.start() 24 25 for i in range(10): 26 t_conn = Thread(target=conn_mysql,args=(e,i)) 27 t_conn.start()

    #

    条件(Condition())

    from threading import Condition
    条件是让程序员自行去调度线程的一个机制
    # Condition涉及4个方法
    # acquire()
    # release()
    # wait() 是指让线程阻塞住
    # notify(int) 是指给wait发一个信号,让wait变成不阻塞
    # int是指,你要给多少给wait发信号

     

     定时器:

    from threading import Timer
    # Timer(time,func)
    # time:睡眠的时间,以秒为单位
    # func:睡眠时间之后,需要执行的任务

    from threading import Timer# 定时器
    
    
    def func():
        print('就是这么nb!')
    
    Timer(2.5,func).start()
    # Timer(time,func)
    # time:睡眠的时间,以秒为单位
    # func:睡眠时间之后,需要执行的任务
  • 相关阅读:
    怎么说???
    再给自己一点鼓励
    还是不要看新闻的好
    系统架构师
    朋友
    未来的路
    I now have a dream
    纪念死去的手机
    全局规划
    终于要上战场了!
  • 原文地址:https://www.cnblogs.com/hfbk/p/9539010.html
Copyright © 2020-2023  润新知