1.啥是多任务
简单地说,就是同时可以运行多个任务。
1.如果一个操作系统上同时运行了多个程序,那么称这个操作系统是多任务的操作系统,Windows,Ubuntu,Android,ios
2.如果一个程序,它可以同时执行多个事情,那么就称为多任务的程序
from time import sleep
import threading
def sing():
for i in range(3):
print('正在唱歌......%d',i)
sleep(1)
def dance():
for i in range(3):
print('正在跳舞.....%d',i)
sleep(1)
if __name__=='__main__':
t1=threading.Thread(target=sing)
t2=threading.Thread(target=dance)
t1.start()
t2.start()
2.多任务执行的原理
1.一个cpu是单核默认可以执行一个程序,如果想要多个程序一起执行,理论上需要多个cpu来执行
2.如果一个cpu是4核,理论上将同时只能有4个任务一起执行,但是事实上却可以运行很多个程序,之所以有这个现象,是因为操作系统控制着cpu,让cpu做了一个特殊的事情,一会运行一个程序,然后快速的运行另外一个程序,再运行另外的程序,依次类推,实现了多个任务看上去“”“一起”运行
2.1假的多任务
操作系统为了让多个程序,都能够得到执行的机会,采用了一系列的方案来实现,例如:时间片调度
3.并发,并行
1.并发:是一个对假的多任务的描述
2.并行:是真的 多任务的描述
4.线程
1.当一个程序运行时,默认有一个线程,这个线程我们称之为主线程
2.多任务也就可以理解为让你的代码再运行的过程中额外创建一些线程,让这些线程去执行代码
4.1 多线程执行
import threading
import time
def say_sorry():
print('亲爱的,我错了,我能吃饭了吗')
time.sleep(1)
for i in range(5):
t=threading.thread(target=say_sorry)
t.start() #启动线程,让线程开始执行
#1.导入threading模块
import threading
import time
def task_1():
while True:
print('1111111')
time.sleep(1)
#2.使用threading模块中的Thread创建一个对象
t1=threading.Thread(target=task_1)
#3.调用这个实例对象的start方法让这个线程开始运行
t1.start()
while True:
print('222222')
time.sleep(1)
#1.导入threading模块
import threading
import time
def task_1():
while True:
print('1111111')
time.sleep(1)
def task_2():
while True:
print('333333')
time.sleep(0.2)
#2.使用threading模块中的Thread创建一个对象
t1=threading.Thread(target=task_1)
t2=threading.Thread(target=task_2)
#3.调用这个实例对象的start方法让这个线程开始运行
t1.start()
t2.start()
while True:
print('222222')
time.sleep(1)
小结
1.想要执行一个单独的任务,那么就需要创建一个新的线程
2.在python中使用threading模块中的Thread类,就可以创建一个对象 这个对象标记着线程,创建出来的线程默认是不会执行的
3.调用这个线程对象的start方法,就可以让这个新的线程开始执行代码。至于这个线程去执行哪里的代码,要看在用Thread创建对象的时候给target参数传递的是哪个函数的引用,即将来线程就会执行target参数指定的那个函数
4.如果想在一个程序中有多个任务一起运行,那么就想办法创建多Thread对象即可
4.2多个线程执行相同的函数:
import time
import threading
def say_sorry():
for i in range(5):
print('i am sorry')
time.sleep(1)
t1=threading.Thread(target=say_sorry)
t2=threading.Thread(target=say_sorry)
t1.start()
t2.start()
小结
1.一个程序中,可以有多个线程,执行相同的代码 但是每个线程执行每个线程的功能,互补影响,仅仅是做的事情相同罢了
2.当在创建Thread对象是target执行的函数的代码执行完之后,意味着这个子线程接收
3.虽然主线程没有了代码,但是它依然会等待所有的子线程结束之后它才会真正的结束,原因是:主线程有个特殊的功能用来对子线程产生的垃圾进行回收处理
4.当主线程接收之后,才意味着整个程序真正的结束
5.多线程执行的顺序不确定
import threading
from time import sleep,ctime
def test1():
#这是一个单独的任务
for i in range(10):
print('任务1...%d',i)
sleep(0.1)
def test2():
#另一个单独的任务
for i in range(5):
print('任务二...%d',i)
sleep(0.2)
t1=threading.Thread(target=test1)
t2=threading.Thread(target=test2)
t1.start()
t2.start()
多线程执行的顺序是不确定,因为在执行代码的时候当前的运行环境可能不同意及资源的分配可能不同,导致了操作系统在计算接下来应该调用哪个程序的时候得到了不一样的答案,因此顺序不确定
6.查看当前程序运行时的线程
import threading
import time
print(threading.enumerate())
def task_1():
for i in range(5):
print('11111')
time.sleep(1)
t=threading.Thread(target=task_1)
t.start()
print(threading.enumerate())
time.sleep(6)
print(threading.enumerate())
小结
1.通过第4行的能够说明,当程序运行之后默认有1个线程
2.当第13行创建一个Thread对象,第14行运行这个对象且在第16行打印的时候有2个线程,那么说明Thread真的是创建了一个线程
3.当一个线程结束之后,在第19行打印时只有1个,那就表明刚刚那个子线程已经结束了
import threading
import time
print(threading.enumerate())
def task_1():
for i in range(5):
print('11111')
time.sleep(1)
t=threading.Thread(target=task_1)
print(threading.enumerate())
t.start()
print(threading.enumerate())
time.sleep(6)
print(threading.enumerate())
小结
1.通过第14行,17行的打印不同说明了,创建一个Thread对象根本不会创建一个线程,仅仅是一个对象罢了而当调用它的start方法之后,才会真正创建一个新的子线程
2.什么时候调用start什么时候才会真正的创建新线程
7.创建线程时传递参数
import threading
def print_lines(num):
for i in range(num):
print('11111')
time.sleep(0.1)
def print_lines2(num1,num2):
for i in range(num1):
print('22222')
time.sleep(0.1)
for i in range(num2):
print('333333')
time.sleep(0.1)
t1=threading.Thread(target=print_lines,args=(5,))
t2=threading.Thread(target=print_lines2,args=(3,4))
t1.start()
t2.start()
小结
1.创建Thread对象的时候:
target指明线程将来去哪里执行代码,args指明线程去执行代码的时候携带的参数是一个元组
2.如果target指明的函数只有1个形参,那么args的元组中必须只有1个元素。如果target指明的函数有2个形参,那么args的元组中必须有2个元素
import threading
def print_lines(num):
for i in range(num):
print('11111')
time.sleep(0.1)
def print_lines2(num1,num2):
for i in range(num1):
print('22222')
time.sleep(0.1)
for i in range(num2):
print('333333')
time.sleep(0.1)
def work2(num1,num2,num3,n):
print('---in work1--num1=%d,num2=%d,num3=%d,n=%d-'%(num1,num2,num3,n))
t1=threading.Thread(target=print_lines,args=(5,))
t2=threading.Thread(target=print_lines2,args=(3,4))
t3=threading.Thread(target=work2,args=(11,22,33),kwargs={"n":44})
#t3=threading.Thread(target=work2,args=(11,22),kwargs={"n":44,"num3":33})
t1.start()
t2.start()
t3.start()
8.多任务-线程
8.1 可以同时收发消息的udp聊天程序
import socket
import threading
def send_msg(upd_socket):
'''获取键盘数据,并将其发送给对方'''
while True:
#2.输入对方的ip地址
dest_ip=input('\n请输入对方的ip地址:')
#3.输入对方的port
dest_port=int(input('\n请输入对方的port:'))
while True:
#1.从键盘输入数据
msg=input('\n请输入要发送的数据:')
if msg:
#4.发送数据
upd_socket.sendto(msg.encode('utf-8'),(dest_ip,dest_port))
else:
break
def recv_msg(upd_socket):
'''接收数据并显示'''
while True:
#1.接收数据
recv_msg=upd_socket.recvfrom(1024)
#2.解码
recv_ip=recv_msg[1]
recv_msg=recv_msg[0].decode('utf-8')
#3.显示接收到的数据
print('>>>%s:%s'%(str(recv_ip),recv_msg))
def main():
#1.创建套接字
udp_socket=socket.socket((socket.AF_INET,socket.SOCK_DGRAM))
#2.绑定本地信息
udp_socket.bind(('',7890))
send_msg_t=threading.Thread(target=send_msg,args=(udp_sockert,))
recv_msg_t=threading.Thread(target=recv_msg,args=(udp_sockert,))
send_msg_t.start()
recv_msg_t.start()
'''
while True:
#3.选择功能
print('*'*30)
print('1:发送消息')
print('2:接收消息')
print('*'*30)
op_num=input('请输入要操作的功能序号:')
#4.根据选择调用相应的函数
if op_num=='1':
send_msg(upd_socket)
elif op_num=='2':
recv_msg(upd_socket)
else:
print('输入有误,重新输入')
'''
if __name__=='__main__':
main()
9.创建线程的另一种方式
1.之前创建线程的方式
import threading
def xxx():
pass
def yyy():
pass
def task_1(num,num2):
xxx()
yyy()
t=threading.Thread(target=task_1,args=(11,),kwargs={'num2':yyy})
t.start() #真正创建线程
2.使用类的方式创建线程
import threading
class UDP(threading.Thread):
def run(self):
pass
u_t=UDP()
u_t.start()
9.1通过继承Thread类创建线程
import time
import threading
class Task(threading.Thread):
def run(self):
while True:
print('11111')
time.sleep(1)
t=Task()
t.start()
while True:
print('main')
time.sleep(1)