python线程的多任务编程
线程
多任务
多任务介绍
对于人来说,一边听歌,一边跳舞就是多任务。
对于电脑,简单的说,同一时间执行多个程序处理数据叫做多任务
多任务理解
单核CPU
单核cpu在处理多任务的时候是根据时间片轮转的方式进行的,比如执行QQ1us,然后切换微信执行1us,最后是执行钉钉1us,如此循环。因为cpu的切换速度过快,导致我们认为三个软件是同时执行的
多核cpu
并发:当cpu不能同时执行当前所有任务时,就会循环执行,是假的多任务
并行:当cpu可以同时执行当前所有任务时,是真的多任务
多任务的实现方式
实现多任务有三种方式:
- 线程
- 进程
- 协程
线程
线程介绍
线程是指在一个单独进程中,对于CPU和内存而言的多个工作单位,所有线程在进程中的资源都是共享的,包括全局数据、执行代码等。
线程的使用
- 先介绍三个方法
- setDaemon(True): 主线程A中,创建了子线程B,并且在主线程A中调用了B.setDaemon(),这个的意思是,把主线程A设置为守护线程,这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出.
- join(): 主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后,才可以接着往下执行
- enumerate(): 查看线程数量
使用
-
代码示例
import threading import datetime def A(): print('函数A') print(datetime.datetime.now()) def B(): print('函数B') print(datetime.datetime.now()) if __name__ == '__main__': # 指定线程到A()和B()函数里执行 t1 = threading.Thread(target=A) t2 = threading.Thread(target=B) # 执行线程 t1.start() t2.start() print('--end--')
从输出结果可以知道,两个线程是在同一时间一起执行的。不过因为抢占式的特点,最后一条语句print('--end--')
有时会在子线程的前面执行。
join()方法的使用
如果我们想让print('--end--')
在最后执行,可以用到join()
方法,当子线程结束后,主线程才会结束。
- join方法的使用,代码示例
import threading
import datetime
def A():
print('函数A')
print(datetime.datetime.now())
def B():
print('函数B')
print(datetime.datetime.now())
if __name__ == '__main__':
# 指定线程到A()和B()函数里执行
t1 = threading.Thread(target=A)
t2 = threading.Thread(target=B)
# 执行线程
t1.start()
t2.start()
t1.join()
t2.join()
print('--end--')
setDaemon()方法的使用
如果不想让主线程等待子线程完成后才结束,可以使用setDaemon
-
代码示例
import threading import time def A(): for i in range(3): print("A") time.sleep(1) if __name__ == '__main__': t1 = threading.Thread(target=A) t1.setDaemon(True) # 要放在线程开始之前 t1.start()
enumerate()的使用,查看线程数量
-
代码示例
import threading import datetime def A(): print('函数A') print(datetime.datetime.now()) def B(): print('函数B') print(datetime.datetime.now()) if __name__ == '__main__': # 创建两个主线程,指定线程到A()和B()函数里执行 t1 = threading.Thread(target=A) t2 = threading.Thread(target=B) # 执行线程 t1.start() t2.start() print(threading.enumerate()) print('--end--')
子线程的创建与执行
当我们调用start()方法时,子线程才会被创建,并且执行
继承Thread类创建线程
我们可以通过修改Thread类的run()方法里的代码,来完成重写run()方法
-
代码示例
import threading class T(threading.Thread): def run(self): self.a() def a(self): for i in range(3): print('a') if __name__ == '__main__': t1 = T() t1.start() # 当调用start()方法时,会主动调用run()方法
当我们调用start()方法时,会主动调用run()方法
多线程共享全局变量
-
代码示例
import threading def a(): global num num += 1 print(f'a:{num}') def b(): print(f'b:{num}') if __name__ == '__main__': num = 10 print(num) t1 = threading.Thread(target=a) t2 = threading.Thread(target=b) t1.start() t2.start() print(num)
线程的传参
当用线程去函数里执行代码时,我们可以看到函数后边是没有括号()的,所以涉及到传参的时候我们该怎么解决这个问题?
-
解决方法
- 我们可以使用args参数进行传参,参数为元组
- 当我们想要传入字典时,可以使用kwargs进行传入
-
代码示例
import threading def a(x): print(x) def b(**kwargs): print(kwargs) if __name__ == '__main__': num = 1 # 使用args参数进行传参 t1 = threading.Thread(target=a, args=(num,)) # 使用kwargs参数进行传入字典 t2 = threading.Thread(target=b, kwargs={"A": 1}) t1.start() t2.start()
线程的资源抢占
-
代码示例
import threading def a(x): global num for i in range(x): num += 1 print(f'a: {num}') def b(x): global num for i in range(x): num += 1 print(f'b: {num}') if __name__ == '__main__': num = 100 t1 = threading.Thread(target=a, args=(1000000, )) t2 = threading.Thread(target=b, args=(1000000, )) t1.start() t2.start() print(num)
运行结果
正常的结果应该是2000100,但是因为资源抢占导致数据不正确,使用锁就可以避免这个问题,下篇博客我会细讲怎么解决这个问题。
最后,有喜欢博主写的内容的伙伴可以点赞收藏加关注哦!
本文地址:https://blog.csdn.net/weixin_44604586/article/details/107091271
上一篇: Python如何搭建代理池
下一篇: 软文需要好的思路和推广工具