一、线程的使用
1.调用函数
import threading, time
def test1():
for i in range(5):
print('---{}---'.format(str(round(time.time(),2))))
time.sleep(0.5)
def test2(name):
for i in range(5):
print('==={}==={}'.format(str(round(time.time(),2)), name))
time.sleep(0.8)
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2,args=('now is',)) #指定一个函数,如果有参数使用args,
#这里一定要有逗号,用括号
t1.start()
t2.start()
output----------------------------------
---1547223781.57---
===1547223781.57===now is
---1547223782.07---
===1547223782.37===now is
---1547223782.57---
---1547223783.07---
===1547223783.17===now is
---1547223783.57---
===1547223783.98===now is
===1547223784.78===now is
2.在类中的调用
start自动 使用run()方法,没有run是无法调用的
import threading, time
class Test(threading.Thread):
def run(self):
self.test1()
self.test2()
def test1(self):
for i in range(5):
print('---{}---'.format(str(round(time.time(),2))))
time.sleep(0.5)
def test2(self):
for i in range(5):
print('=== ===')
time.sleep(0.8)
t = Test()
t.start()
# output
---1547973227.31---
---1547973227.81---
---1547973228.31---
---1547973228.81---
---1547973229.31---
=== ===
=== ===
=== ===
=== ===
=== ===
3.多线程的资源竞争问题
在共享全局变量时,线程会存在资源竞争的问题,根本原因在于cpu将一个命令分成多步执行,就像下面这个例子可能会储存两次相同的值。
import threading
num = 0
def test1(times):
global num # 声明全局变量
for i in range(times):
num += 1
def test2(times):
global num
for i in range(times):
num += 1
t1 = threading.Thread(target=test1, args=(50000,))
t2 = threading.Thread(target=test2, args=(50000,))
t1.start()
t2.start()
print(num)
98125而不是100000
这个问题我还有点不懂的地方,就是当我传的不是50000,而是500000时,结果应当在50万与100万之间时,最后的输出却只有20万。后来我还是没搞懂,其中一个线程可以比另外一个慢一些,之后保存的值会比覆盖前面保存的值
,那至少也执行了50万次加一和储存鸭。
另外一个问题就是,在类中继承中 init 最好不要声明,这可能会导致父类方法无法使用。
解决方法:互斥锁
1.创建锁
mutex = threading.Lock()
2.锁定
mutex.acquire()
3.释放
mutex.release()
可以有多个锁,但是要尽量避免死锁,考虑银行家算法 and 超时时间(超过了就不上锁了)
一个聊天的应用
import socket,threading
def recv_msg(udp_socket):
# 接受数据
while True:
recv_data = udp_socket.recvfrom(1024)
print(recv_data)
def send_msg(udp_socket, desk_ip, desk_port):
# 发送数据
while True:
send_data = input("请输入发送的数据")
udp_socket.sendto(send_data.encode("utf-8"),(desk_ip, desk_port))
def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定ip
udp_socket.bind(("", 7090))
desk_ip = input("输入ip")
desk_port = int(input("输入对方port"))
# 创建两个线程
t_recv = threading.Thread(target=recv_msg, args=(udp_socket,))
t_send = threading.Thread(target=send_msg, args=(udp_socket, desk_ip, desk_port,))
t_recv.start()
t_send.start()
main()
判断线程是否完成
https://python3-cookbook.readthedocs.io/zh_CN/latest/c12/p01_start_stop_thread.html
if t.is_alive():
print('Still running')
else:
print('Completed')
二、进程的使用
1.简单例子:只需要变一个地方
import multiprocessing, time
def test1(times):
num = 0
for i in range(times):
num += 1
print(num,'======')
def test2(times):
num = 0
for i in range(times):
num += 1
print(num,'------')
t1 = multiprocessing.Process(target=test1, args=(50,))
t2 = multiprocessing.Process(target=test2, args=(50,))
t1.start()
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
#!/usr/bin/python3
import multiprocessing, time
def test1():
n = 0
while True:
n+=1
print(n, '----')
time.sleep(1)
def test2():
num = 0
while True:
num+=1
print(num, '====')
time.sleep(1)
if __name__ == '__main__':
t1 = multiprocessing.Process(target=test1)
t2 = multiprocessing.Process(target=test2)
t1.start()
t2.start()
# output
1 ----
1 ====
2 ----
2 ====
3 ----
3 ====
4 ----
省略...
2.进程和线程的区别
进程是资源分配的单位,线程是任务调度的单位。多线程相当于是一个桌子上很多人在一起吃饭,多进程相当于很多个桌子很多人在吃饭。
必须先有进程 才有线程,没有进程就没有线程。
3.队列的使用
队列基础方法
import multiprocessing
q = multiprocessing.Queue(3) # 创建一个容量为3的队列
q.put('123') # 放入数据
a = q.get() # 获取数据
当队列满了
q.full() # True
当队列空了
q.empty() # True
使用—进程间的通信
4.进程池的使用
为什么要用进程池
由于任务太多,不可能每一个都创建一个进程去做,创建和销毁进程也是需要消耗资源的。而进程池就可以将多个任务一次放入进程池中的n个进程中,让其做完后去做下一个任务。
使用pool
以上代码中 join非常重要,因为如果没有阻塞,当代码执行完end时,主进程就杀死了,然鹅其中的子进程并没有执行完毕。
output: