zoukankan      html  css  js  c++  java
  • 网络编程------线程相关问题.

    线程与进程的区别:

    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:睡眠时间之后,需要执行的任务
  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/hfbk/p/9539010.html
Copyright © 2011-2022 走看看