一、线程的使用

1.调用函数

  1. import threading, time
  2. def test1():
  3. for i in range(5):
  4. print('---{}---'.format(str(round(time.time(),2))))
  5. time.sleep(0.5)
  6. def test2(name):
  7. for i in range(5):
  8. print('==={}==={}'.format(str(round(time.time(),2)), name))
  9. time.sleep(0.8)
  10. t1 = threading.Thread(target=test1)
  11. t2 = threading.Thread(target=test2,args=('now is',)) #指定一个函数,如果有参数使用args,
  12. #这里一定要有逗号,用括号
  13. t1.start()
  14. t2.start()
  15. output----------------------------------
  16. ---1547223781.57---
  17. ===1547223781.57===now is
  18. ---1547223782.07---
  19. ===1547223782.37===now is
  20. ---1547223782.57---
  21. ---1547223783.07---
  22. ===1547223783.17===now is
  23. ---1547223783.57---
  24. ===1547223783.98===now is
  25. ===1547223784.78===now is

2.在类中的调用

start自动 使用run()方法,没有run是无法调用的

  1. import threading, time
  2. class Test(threading.Thread):
  3. def run(self):
  4. self.test1()
  5. self.test2()
  6. def test1(self):
  7. for i in range(5):
  8. print('---{}---'.format(str(round(time.time(),2))))
  9. time.sleep(0.5)
  10. def test2(self):
  11. for i in range(5):
  12. print('=== ===')
  13. time.sleep(0.8)
  14. t = Test()
  15. t.start()
  16. # output
  17. ---1547973227.31---
  18. ---1547973227.81---
  19. ---1547973228.31---
  20. ---1547973228.81---
  21. ---1547973229.31---
  22. === ===
  23. === ===
  24. === ===
  25. === ===
  26. === ===

3.多线程的资源竞争问题

在共享全局变量时,线程会存在资源竞争的问题,根本原因在于cpu将一个命令分成多步执行,就像下面这个例子可能会储存两次相同的值。

  1. import threading
  2. num = 0
  3. def test1(times):
  4. global num # 声明全局变量
  5. for i in range(times):
  6. num += 1
  7. def test2(times):
  8. global num
  9. for i in range(times):
  10. num += 1
  11. t1 = threading.Thread(target=test1, args=(50000,))
  12. t2 = threading.Thread(target=test2, args=(50000,))
  13. t1.start()
  14. t2.start()
  15. print(num)
  16. 98125而不是100000

image.png
这个问题我还有点不懂的地方,就是当我传的不是50000,而是500000时,结果应当在50万与100万之间时,最后的输出却只有20万。后来我还是没搞懂,其中一个线程可以比另外一个慢一些,之后保存的值会比覆盖前面保存的值
,那至少也执行了50万次加一和储存鸭。
另外一个问题就是,在类中继承中 init 最好不要声明,这可能会导致父类方法无法使用。

解决方法:互斥锁

1.创建锁
mutex = threading.Lock()
2.锁定
mutex.acquire()
3.释放
mutex.release()
image.png
可以有多个锁,但是要尽量避免死锁,考虑银行家算法 and 超时时间(超过了就不上锁了)

一个聊天的应用

  1. import socket,threading
  2. def recv_msg(udp_socket):
  3. # 接受数据
  4. while True:
  5. recv_data = udp_socket.recvfrom(1024)
  6. print(recv_data)
  7. def send_msg(udp_socket, desk_ip, desk_port):
  8. # 发送数据
  9. while True:
  10. send_data = input("请输入发送的数据")
  11. udp_socket.sendto(send_data.encode("utf-8"),(desk_ip, desk_port))
  12. def main():
  13. # 创建套接字
  14. udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  15. # 绑定ip
  16. udp_socket.bind(("", 7090))
  17. desk_ip = input("输入ip")
  18. desk_port = int(input("输入对方port"))
  19. # 创建两个线程
  20. t_recv = threading.Thread(target=recv_msg, args=(udp_socket,))
  21. t_send = threading.Thread(target=send_msg, args=(udp_socket, desk_ip, desk_port,))
  22. t_recv.start()
  23. t_send.start()
  24. main()

image.pngimage.png

判断线程是否完成

https://python3-cookbook.readthedocs.io/zh_CN/latest/c12/p01_start_stop_thread.html

  1. if t.is_alive():
  2. print('Still running')
  3. else:
  4. print('Completed')

二、进程的使用

1.简单例子:只需要变一个地方

  1. import multiprocessing, time
  2. def test1(times):
  3. num = 0
  4. for i in range(times):
  5. num += 1
  6. print(num,'======')
  7. def test2(times):
  8. num = 0
  9. for i in range(times):
  10. num += 1
  11. print(num,'------')
  12. t1 = multiprocessing.Process(target=test1, args=(50,))
  13. t2 = multiprocessing.Process(target=test2, args=(50,))
  14. t1.start()
  15. t2.start()

如果你的代码在windows上报错:

The “freeze_support()” line can be omitted if the program is not going to be。。。

在执行时添加 if name == ‘main‘:
参考:https://blog.csdn.net/Solo95/article/details/78913709

  1. #!/usr/bin/python3
  2. import multiprocessing, time
  3. def test1():
  4. n = 0
  5. while True:
  6. n+=1
  7. print(n, '----')
  8. time.sleep(1)
  9. def test2():
  10. num = 0
  11. while True:
  12. num+=1
  13. print(num, '====')
  14. time.sleep(1)
  15. if __name__ == '__main__':
  16. t1 = multiprocessing.Process(target=test1)
  17. t2 = multiprocessing.Process(target=test2)
  18. t1.start()
  19. t2.start()
  20. # output
  21. 1 ----
  22. 1 ====
  23. 2 ----
  24. 2 ====
  25. 3 ----
  26. 3 ====
  27. 4 ----
  28. 省略...

2.进程和线程的区别

进程是资源分配的单位,线程是任务调度的单位。多线程相当于是一个桌子上很多人在一起吃饭,多进程相当于很多个桌子很多人在吃饭。
必须先有进程 才有线程,没有进程就没有线程。

3.队列的使用

队列基础方法

  1. import multiprocessing
  2. q = multiprocessing.Queue(3) # 创建一个容量为3的队列
  3. q.put('123') # 放入数据
  4. a = q.get() # 获取数据
  5. 当队列满了
  6. q.full() # True
  7. 当队列空了
  8. q.empty() # True

使用—进程间的通信

image.pngimage.png

4.进程池的使用

为什么要用进程池

由于任务太多,不可能每一个都创建一个进程去做,创建和销毁进程也是需要消耗资源的。而进程池就可以将多个任务一次放入进程池中的n个进程中,让其做完后去做下一个任务。

使用pool

image.png
以上代码中 join非常重要,因为如果没有阻塞,当代码执行完end时,主进程就杀死了,然鹅其中的子进程并没有执行完毕。
output:
image.png