单核多任务:时间片轮转;用户端感觉多个任务同步执行。
- 并行:真的多任务;任务数 <= cpu核数
- 并发:假的多任务;任务数 > cpu核数
线程:threading模块
- 线程:一个程序运行起来之后,一定有个执行代码的东西,这个东西就称为线程
- enumerate 拆包:返回的是元组
创建函数和类的线程
threading.Thread(target = 函数名) #创建函数的线程
class 类名(threading.Thread): #创建类线程
def run(self):
pass
t = 类名()
t.start() # start调用run()
global ** 修改全局变量
- 在一个函数中对全局变量修改时,如果修改了指向,即全局变量指向一个新的地方,那么必须使用global
- 如果仅仅修改了指向空间的数据,此时可以不用global说明。
- 示例代码:
import threading
import time
g_num = 100
g_num2 = [11, 22]
def test1(temp):
global g_num
g_num += 1
print("-----in test1 g_num = %d-----" % g_num)
temp.append(33)
print("-----in test1 temp = %s-----" % str(temp))
def test2(temp):
print("-----in test2 g_num = %d-----" % g_num)
print("-----in test1 temp = %s-----" % str(temp))
def main():
# target指定将来这个线程去哪个函数执行代码
# args 指定将来调用函数的时候传递什么数据过去(实参) 数据是元组
t1 = threading.Thread(target = test1, args=(g_num2,))
t2 = threading.Thread(target = test2, args=(g_num2,))
t1.start()
time.sleep(1)
t2.start()
time.sleep(1)
print("-----in main Threah g_num = %d-----" % g_num)
print("-----in main Threah g_num2 = %s-----" % str(g_num2))
if __name__ == "__main__":
main()
- 运行结果
-----in test1 g_num = 101-----
-----in test1 temp = [11, 22, 33]-----
-----in test2 g_num = 101-----
-----in test1 temp = [11, 22, 33]-----
-----in main Threah g_num = 101-----
-----in main Threah g_num2 = [11, 22, 33]-----
[Finished in 2.5s]
互斥锁:
- 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制(上锁~解锁)
- 注意避免死锁的方法:
- 程序设计时要尽量避免(银行家算法)
- 设置超时时间
- 示例代码:
import threading
import time
# 定义全局变量
g_num = 0
mutex = threading.Lock()
def test1(num):
global g_num
# 上锁,如果之前没有被上锁,那么此时上锁成功
# 如果之前已经上锁,那么此时会堵塞,知道前一个锁解开
for i in range(num):
#mutex.acquire()
g_num += 1
# 解锁
#mutex.release()
print("-----in test1 g_num = %d-----" % g_num)
def test2(num):
global g_num
# 上锁,如果之前没有被上锁,那么此时上锁成功
# 如果之前已经上锁,那么此时会堵塞,知道前一个锁解开
for i in range(num):
#mutex.acquire()
g_num += 1
# 解锁
#mutex.release()
print("-----in test2 g_num = %d-----" % g_num)
def main():
t1 = threading.Thread(target=test1, args=(10000000,))
t2 = threading.Thread(target=test2, args=(10000000,))
t1.start()
t2.start()
time.sleep(5)
print("-----in main Thread g_num = %d-----" % g_num)
if __name__ == '__main__':
main()
- 运行结果
-----in test1 g_num = 11246796-----
-----in test2 g_num = 11281556-----
-----in main Thread g_num = 11281556-----
[Finished in 5.2s]
多任务版udp聊天器
# 多任务版udp聊天器
import socket
import threading
def recv_msg(udp_socket):
"""接收并显示数据"""
# 接接收数据
while True:
recv_data = udp_socket.recvfrom(1024)
print(recv_data[0].decode("utf-8"))
def send_msg(dest_ip, dest_port,udp_socket):
"""发送数据"""
while True:
send_data = input("请输入要发送的数据:\n")
udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
def main():
"""完成udp聊天的整体控制"""
# 1.创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.绑定本地信息
dest_ip0 = input("请输入自己的ip:")
dest_port0 = int(input("请输入自己的port:"))
localaddr = (dest_ip0, dest_port0)
udp_socket.bind(localaddr)
# 3.获取对方地址
dest_ip1 = input("请输入对方的ip:")
dest_port1 = int(input("请输入对方的port:"))
# 4.创建2个线程,去执行相应的功能
t_recv = threading.Thread(target = recv_msg,args = (udp_socket,))
t_send = threading.Thread(target = send_msg,args =(dest_ip1, dest_port1,udp_socket))
t_recv.start()
t_send.start()
Python下的多线程处理
Python多线程的原理与实现