1、线程与进程基本概念
2、同步与异步
3、并发与并行
当用户在操作系统中启动某一个程序中,启动了至少一个进程,程序是一种静态资源实体,只是一系列代码。
进程是动态的,当操作系统将程序数据载入内存时,创建一个动态实体,对各种资源进行操作。
程序(静态) + 数据集 = 进程(运行时)
不同进程之间不共享内存,一个进程包含至少一个或多个线程
多个线程之间共享一个进程的内存,没有控制好,容易出现竞争状态,为了避免这种状态,出现互斥锁、信号量等机制
互斥锁是指一个线程使用某一内存空间会获得的一把锁,使用锁将内存空间锁起来,其他线程只有等当前线程使用完毕并将锁
释放,才能使用该内存空间中的资源。
信号量用来指定某一内存空间通常可以被多少个线程使用。如当信号量为4时,内存空间中最多能同时存在4个线程,某个线程操作完
内存空间中的资源后,信号量会自增1,允许其他线程进入到该内存空间
同步与异步
同步是指不同程序单元为了完成某个任务通过某种方式协调一致,异步是指不需要协调也可独立完成。
‘’’
并发是指有限物理资源尽可能处理多个任务
‘’’
from flask import Flask
import time
app = Flask(__name__)
def longtime(s):
time.sleep(s)
@app.route('/index')
def index():
longtime(10)
return 'hello sync flask'
if __name__ == '__main__':
app.run()
#通过性能池实现
import time
from concurrent.futures import ThreadPoolExecutor
from flask import Flask
executor = ThreadPoolExecutor(2)#创建线程池大小为2
app = Flask(__name__)
def longtime(s):
time.sleep(s)
@app.route('/index')
def index():
executor.submit(longtime,10)
return 'hello async flask'
if __name__ == '__main__':
app.run()
‘’’
在python中有三种使用线程的方式,分别是thread、threading、ThreadPoolExecutor
threading 有两种方式创建线程
1、创建threading.Thread实例,将需要被线程执行的函数传入该实例
2、创建一个类,继承于threading.Thread,重写run方法
‘’’
import time
import threading
def longTime(s):
time.sleep(s)
def main():
t = threading.Thread(target=longTime,args=[10])
t.start()#start用于启动线程,在同一个线程中不能被多次调用
t.join()#将主线程挂起,直到子线程运行结束
print('Done')#子线程会执行10s,Done在10s后才打印
if __name__ == '__main__':
main()
import time
import threading
class MyThread(threading.Thread):
def __init__(self,func,args,tname = ''):
#super (MyThread,self).__init__()
super().__init__()
self.tname = tname
self.func = func
self.args = args
def run(self):
self.func(*self.args)
def longtime(s):
time.sleep(s)
def main():
t = MyThread(longtime,(10,),longtime.__name__)
t.start()
t.join()
if __name__ == '__main__':
main()
#ThreadPoolExecutor使用
#相比threading等模块,该模块通过submit返回一个future对象,通过它主线程(进程)中可以获取某一个
#线程(进程)执行的状态或者某一任务执行的状态及返回值
import time
import random
from concurrent.futures import ThreadPoolExecutor,as_completed
def spider(url):
'''
爬虫方法
:param url:
:return:
'''
time.sleep(random.randint(1,5))
print(f'crawl task {url} finished')
return url
#创建一个最大容纳数量为5的线程池
with ThreadPoolExecutor(max_workers=5) as executor:
urls = ['https://abc.com','https://efg.com','https://hij.com','https://klm.com'
,'https://nop.com','https://rsz.com']
all_task = []
for url in urls:#将任务提交到线程池
task = executor.submit(spider,url)
#将任务添加到对象列表
all_task.append(task)
#阻塞,获得任务完成后的返回值
for future in as_completed(all_task):
result = future.result()
print(f'result:{result}')
print('main_finished')
'''
as_completed()方法是一个生成器,在没有完成任务的时候,会一直阻塞,除非设置了timeout
当有某个任务完成的时候,会yield这个任务,就能执行for循环下的语句,然后继续阻塞,循环到所有的任务结束
同时,先完成的任务会返回给主线程
‘’’