粗浅理解:
- 程序: /bin/firefox是一个二进制程序, (eg:python, Java程序), 是一个真实存在的, 可以看到的实体;
- 进程: 执行程序的过程中产生的一系列内容,(计算机给进程分配了内存, cpu等…)
- 线程: 是执行进程
专业的总结:
- 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,
是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 - 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。
是被系统独立调度和分派的基本单位。
1.创建线程
一个进程里面必然有一个主线程
操作线程的模块:
thread
threading
import _thread
import threading
import time
def job():
print("这是一个需要执行的任务。。。。。")
print("当前线程的个数:", threading.active_count() )
print("当前线程的信息:", threading.current_thread())
time.sleep(100)
if __name__ == '__main__':
job()
2.实现多线程的方法
(1)第一种(不常用):
import threading
import time
import _thread
def job():
print("这是一个需要执行的任务。。。。。")
print("当前线程的个数:", threading.active_count() )
print("当前线程的信息:", threading.current_thread())
time.sleep(100)
if __name__ == '__main__':
# c创建多线程时, 需要制定该线程执行的任务
_thread.start_new_thread(job, ())
_thread.start_new_thread(job, ())
# job()
while True:
pass
(2)第二种:
import threading
import time
import _thread
def job():
print("这是一个需要执行的任务。。。。。")
print("当前线程的个数:", threading.active_count() )
time.sleep(1)
print("当前线程的信息:", threading.current_thread())
if __name__ == '__main__':
# c创建多线程时, 需要制定该线程执行的任务
t1 = threading.Thread(target=job )
t2 = threading.Thread(target=job)
t1.start()
t2.start()
print(threading.active_count())
# 出现的问题: 主线程执行结束, 但是子线程还在运行。
# 等待所有的子线程执行结束之后, 再执行主线程
t1.join()
t2.join()
print("程序执行结束.....")
(3)第三种(继承):
import threading
import time
import _thread
class MyThread(threading.Thread):
def __init__(self, jobName):
super(MyThread, self).__init__()
self.jobName = jobName
# 重写run方法, 实现多线程, 因为start方法执行时, 调用的是run方法;
# run方法里面编写的内容就是你要执行的任务;
def run(self):
print("这是一个需要执行的任务%s。。。。。" %(self.jobName))
print("当前线程的个数:", threading.active_count() )
time.sleep(1)
print("当前线程的信息:", threading.current_thread())
if __name__ == '__main__':
t1 = MyThread("name1")
t2 = MyThread("name2")
t1.start()
t2.start()
t1.join()
t2.join()
print("程序执行结束.....")
3.使用多线程案例与未使用对比
(1)未使用多线程案例
# 1. 简单的爬虫:
import time
from urllib.request import urlopen
def timeit(f):
def wrapper(*args, **kwargs):
start_time = time.time()
res = f(*args, **kwargs)
end_time = time.time()
print("%s函数运行时间:%.2f" % (f.__name__, end_time - start_time))
return res
return wrapper
def get_addr(ip):
url = "http://ip-api.com/json/%s" % (ip)
urlObj = urlopen(url)
# 服务端返回的页面信息, 此处为字符串类型
pageContent = urlObj.read().decode('utf-8')
# 2. 处理Json数据
import json
# 解码: 将json数据格式解码为python可以识别的对象;
dict_data = json.loads(pageContent)
print("""
%s
所在城市: %s
所在国家: %s
""" % (ip, dict_data['city'], dict_data['country']))
@timeit
def main():
ips = ['12.13.14.%s' % (i + 1) for i in range(10)]
for ip in ips:
get_addr(ip)
if __name__ == '__main__':
main()
main函数运行时间:4.15
(2)使用多线程案例
# 1. 简单的爬虫:
import threading
import time
from urllib.request import urlopen
def timeit(f):
def wrapper(*args, **kwargs):
start_time = time.time()
res = f(*args, **kwargs)
end_time = time.time()
print("%s函数运行时间:%.2f" % (f.__name__, end_time - start_time))
return res
return wrapper
def get_addr(ip):
url = "http://ip-api.com/json/%s" % (ip)
urlObj = urlopen(url)
# 服务端返回的页面信息, 此处为字符串类型
pageContent = urlObj.read().decode('utf-8')
# 2. 处理Json数据
import json
# 解码: 将json数据格式解码为python可以识别的对象;
dict_data = json.loads(pageContent)
print("""
%s
所在城市: %s
所在国家: %s
""" % (ip, dict_data['city'], dict_data['country']))
@timeit
def main():
ips = ['12.13.14.%s' % (i + 1) for i in range(10)]
threads = []
for ip in ips:
t = threading.Thread(target=get_addr, args=(ip, ))
threads.append(t)
t.start()
[thread.join() for thread in threads]
if __name__ == '__main__':
main()
main函数运行时间:1.95
结论:使用多线程的案例用时少于未使用的
疑问: python使用多线程, 一定运行速度快么? 为什么?
- GIL(global interpreter lock)
- python解释器中任意时刻都只有一个线程在执行;
- GIL执行过程:
- 1). 设置一个GIL;
- 2). 切换线程去准备执行任务(Runnale就绪状态);
- 3). 运行;
- 4). 可能出现的状态:
- 线程任务执行结束;
- time.sleep()
- 需要获取其他的信息才能继续执行(eg: 读取文件, 需要从网络下载html网页) - 5). 将线程设置为睡眠状态;
- 5). 解GIL的锁;
多线程的应用场景: I/O密集型(input, output) — 爬虫
不建议使用多线程的场景: 计算密集型(cpu一直占用)