一、操作系统/应用程序
a. 硬件
- 硬盘
- CPU
- 主板
- 显卡
- 内存条
- 电源
...
b. 装系统(软件)
- 系统就是一个由程序员写出来的软件, 该软件用于控制计算机的硬件, 让他们之间相互配合.
c. 装软件(安装应用程序)
- QQ
- 百度云
- pycharm
...
二、并发和并行
并发, 伪 由于执行速度特别快, 人感觉不到停顿
并行, 真 创建10个人同时操作.
并行:指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
并发:并发是指资源有限的情况下,两者交替轮流使用资源,比如一个单核cpu资源同时满足一个人使用,A用一会后,让给B,B用完继续给A,交替使用,目的是提高效率;
并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
并发是从宏观上,在一个时间段上可以看成是同时执行的。
三、线程/进程
a. 单进程、 单线程的应用程序
print('666')
b. 到底什么是线程?什么是进程?
Python自己没有这玩意,Python中调用的操作系统的线程和进程
c. 单进程、多线程的应用程序
import threading print('666') def func(arg): print(arg) t = threading.Thread(target=func) t.start()
一个应用程序(软件),可以有多个进程(默认只有一个),一个进程中可以创建多个线程(默认一个)。
d. 故事: Alex甄嬛西游传
总结:
1. 操作系统帮助开发者操作硬件。
2. 程序员写好代码在操作系统上运行(依赖解释器)。
3.当任务特别多,我们可以把以前的写法改进一下:
import threading import requests import uuid url_list = [ 'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg', 'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg', 'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg', ] def task(url): ret = requests.get(url) file_name = str(uuid.uuid4()) + '.jpg' with open(file_name, mode='wb') as f: f.write(ret.content) for url in url_list: task(url) """ - 你写好代码 - 交给解释器运行: python s1.py - 解释器读取代码,再交给操作系统去执行,根据你的代码去选择创建多少个线程/进程去执行(单进程/单线程)。 - 操作系统调用硬件:硬盘、cpu、网卡.... """以前的我们写代码
import threading import requests import uuid url_list = [ 'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg', 'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg', 'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg', ] def task(url): ret = requests.get(url) file_name = str(uuid.uuid4()) + '.jpg' with open(file_name, mode='wb') as f: f.write(ret.content) for url in url_list: t = threading.Thread(target=task, args=(url,)) t.start() """ - 你写好代码 - 交给解释器运行: python s2.py - 解释器读取代码,再交给操作系统去执行,根据你的代码去选择创建多少个线程/进程去执行(单进程/4线程)。 - 操作系统调用硬件:硬盘、cpu、网卡.... """现在的我们写代码
四、Python中线程和进程(GIL锁)
GIL锁(全局解释器锁): 用于限制一个进程中同一时刻只有一个线程被cpu调度。
扩展:默认GIL锁再执行100个cpu指令(过期时间)切换线程。
线程和进程的区别:
线程,线程是cpu工作的最小单元;
进程,进程是cpu资源分配的最小单元,为线程提供一个资源共享的空间;
一个进程中可以有多个线程,一个进程中默认有一个主线程;
Python多线程情况下:
- 计算密集型操作:效率低。(GIL锁)
- IO操作:效率高
Python多进程的情况下:
- 计算密集型操作:效率高(浪费资源)。 不得已而为之。
- IO操作:效率高 (浪费资源)。
以后写Python时:
IO密集型用多线程: 文件/输入输出/socket网络通信
计算密集型用多进程。
扩展:
Java多线程情况下:
- 计算密集型操作:效率高。
- IO操作: 效率高
Python多进程的情况下:
- 计算密集型操作:效率高(浪费资源)。
- IO操作: 效率高 (浪费资源)。
五、线程的使用
1. 线程的基本使用
import threading def func(arg): print(arg) t = threading.Thread(target=func,args=(11,)) # 创建一个子线程 t.start() print(123) # 11 # 123 # 程序结束
2.主线程默认等子线程执行完毕,才结束程序
import threading import time def func(arg): time.sleep(arg) print(arg) t1 = threading.Thread(target=func,args=(3,)) t1.start() t2 = threading.Thread(target=func,args=(9,)) t2.start() print(123) # 3 # 程序开始3秒后 # 6 # 程序开始6秒后 # 程序结束
3、主线程不再等,当主线程终止则所有子线程也终止,使用setDaemon(True)
import threading import time def func(arg): time.sleep(2) print(arg) t1 = threading.Thread(target=func,args=(3,)) t1.setDaemon(False) # 主线程等待此子进程(默认是False等待) t1.start() t2 = threading.Thread(target=func,args=(9,)) t2.setDaemon(True) # 主线程等待此子进程(需要设置) t2.start() print(123)
4、开发者可以控制主线程等待子线程(最多等待时间),使用join(n)
import threading import time def func(arg): time.sleep(arg) print(arg) print("创建子线程t1") t1 = threading.Thread(target=func,args=(3,)) t1.start() # 无参数: 让主线程在这里等着,直到子线程t1执行完毕,才可以往下走. # 有参数: 让主线程在这里最多等n秒,无论是否执行完毕,会继续往下走. t1.join(2) print("创建子线程t2") t2 = threading.Thread(target=func,args=(1,)) t2.start() t2.join(3) # 让主线程在这里等着,最多等待3秒,会继续往下走 print(123) # 创建子线程t1 # 创建子线程t2 # 3 # 1 # 123 # 程序结束
5、线程名称
import threading def func(arg): t = threading.current_thread() # 获取当前执行该函数的线程的对象 name = t.getName() # 根据当前线程对象获取当前线程名称 print(name, arg) t1 = threading.Thread(target=func,args=(11,)) t1.setName('李白') t1.start() t2 = threading.Thread(target=func,args=(22,)) t2.setName('白居易') t2.start() print(123) # 李白 11 # 白居易 22 # 123
6、线程本质
# 先打印:11?123? import threading def func(arg): print(arg) t1 = threading.Thread(target=func,args=(11,)) t1.start() # start 是开始运行线程吗?不是 # start 告诉cpu,我已经准备就绪,你可以调度我了。 print(123)
7、补充: 面向对象版本的多线程
import threading def func(arg): print(arg) t1 = threading.Thread(target=func,args=(11,)) t1.start()常见的创建多线程的方式
import threading class MyThread(threading.Thread): def run(self): print(11111,self._args,self._kwargs) t1 = MyThread(args=(11,)) t1.start() # 在cpu内部,如果要调度这个线程的话会执行这个对象的run方法 t2 = MyThread(args=(22,)) t2.start() print('end') # 11111 (11,) {} # 11111 (22,) {} # end面对对象方式(一般不用,了解即可))
六、Python中线程编写
1. 计算密集型多线程无用
impot threading v1 = [11, 22, 33] # +1 v2 = [44, 55, 66] # +100 def func(data, plus): for i in range(len(data)): data[i] = data[i] + plus t1 = threading.Thread(target=func,args=(v1,1)) t1.start() t2 = threading.Thread(target=func,args=(v2,100)) t2.start()
2. IO操作,多线程有用
import threading import requests import uuid url_list = [
'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg',
'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg', ] def task(url): ret = requests.get(url) file_name = str(uuid.uuid4()) + '.jpg' with open(file_name, mode='wb') as f: f.write(ret.content) for url in url_list: t = threading.Thread(target=task, args=(url,)) t.start()
3. 多线程的问题(加锁和释放锁)
import time import threading lock = threading.RLock() n = 10 def task(i): print('这段代码不加锁',i) lock.acquire() # 加锁,此区域代码同一时刻只能有一个线程执行 global n print('当前线程',i,'读取到的n的值为: ',n) n = i time.sleep(1) print('当前线程',i,'修改的n的值为: ',n) lock.release() # 释放锁 for i in range(10): t = threading.Thread(target=task, args=(i,)) t.start()
总结:
1. 应用程序/进程/线程的关系? *****(面试题: 进程/线程/协程的区别)
工厂,厂房,工人, 工人共享厂房里的所有资源
注意:线程是为了工作
2. 为什么要创建线程?
由于线程是cpu工作的最小单元,创建线程可以利用多核优势实现并行操作(Java/C#).
3. 为什么要创建进程?
进程和进程之间做数据隔离(Java/C#)
注意:进程是为了提高环境让线程工作
4. Python
a. Python中存在一个GIL锁. *****
- 造成: 多线程无法利用多核优势
- 解决: 开多进程处理(浪费资源)
进程和线程如何选择使用?
IO密集型:多线程
计算密集型:多进程
b. 线程的创建
- Thread *****
- MyTread
c. 其他
- join *****
- setDeanon *****
- setName *****
- threading.current_thread() *****
d. 锁
- 加锁
- 释放