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

2021-07-14 10:06

阅读:626

标签:lex   资源分配   运算   线程阻塞   解释器   []   代码段   rgs   语言   

线程与进程的区别:

  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 :
 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(\033[42m 数据库正在维护 \033[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:睡眠时间之后,需要执行的任务

 

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

标签:lex   资源分配   运算   线程阻塞   解释器   []   代码段   rgs   语言   

原文地址:https://www.cnblogs.com/hfbk/p/9539010.html


评论


亲,登录后才可以留言!