Python day17/18
正则,进程,线程
正则
import re
re.search() 扫描,只查一次
re.match()从头匹配
re.split() 分割
re.sub() 替换
re.fullmatch() 整个字符串作为整体查找
re.findall() 查找所有匹配的,以一个列表的形式返回
.group(n)返回第n组
(?P正则表达式)(?P=name)
.+ >=1
*+>=0
?匹配正则后加上?表示{0,1},非贪婪模式
{n,} >=n
{n,m} <=m >=n
[0-9] 匹配数字 \d
\w匹配数字字母下划线 \W相反
^开头
$结尾
\s空格 \S相反
[a-zA-Z] 匹配字母
进程
Process
from multiprocessing import Process
创建进程的方式:
1.p1 = Process(…)
2.自定义进程
class xxxProcess(Process):
def init(self):
Process.init(self)
def run(self):
进程的任务
方法:
run()
start()
join()
close()
terminate()
is_alive()
对全局变量的使用: 每个进程中都会存在一份全局变量
*************自定义进程,重写父类run()方法****************
import os
import time
import requests
from multiprocessing import Process, Queue
class DownloadProcess(Process):
def __init__(self, urls, queue):
Process.__init__(self)
self.urls = urls
self.queue = queue
# 重写父类的run方法
def run(self):
for image_url in self.urls:
filename = os.path.split(image_url)[1]
response = requests.get(image_url)
image_data = response.content
self.queue.put(image_data)
self.queue.get()
print('下载{}完毕'.format(filename))
self.queue.close()
进程池
进程池:
pool = Pool(5)
添加任务:
非阻塞: apply_async() —> 队列
阻塞: apply() —> 阻塞
********阻塞式,非阻塞式********
import os
import time
from multiprocessing import Pool
def task1():
for i in range(5):
print('洗衣服:',i, os.getpid(), os.getppid())
time.sleep(0.5)
# return '我是进程:' + str(os.getpid())
if __name__ == '__main__':
pool = Pool(4)
#
for i in range(10):
pool.apply(task1) # 阻塞式: 进程池中一个任务完成之后才能做下一个任务
pool = Pool(4)
print('------------------------->',i)
# 添加任务结束
pool.close()
# 阻塞主进程
pool.join()
print('main over')
************************
def task1():
print('洗衣服:', os.getpid(), os.getppid())
time.sleep(0.5)
return '我是进程:' + str(os.getpid())
# response = requests.get(url)
# return response.content
def callback(msg):
print('{}洗衣服任务完成!'.format(msg))
# 保存下载的文件到本地
# 非阻塞式
if __name__ == '__main__':
pool = Pool(4)
#for i in range(10):
# pool.apply_async(task1, callback=callback)
#callback=callback是回调函数
进程间通信:
queue = Queue(number)
默认都是阻塞的:
queue.put([timeout=seconds])
queue.get([timeout=seconds])
多进程
多进程适合在CPU 密集型操作(cpu 操作指令比较多,如科学计算,位数多的浮点运算)
多线程适合在IO 密集型操作(读写数据操作较多的,比如爬虫)
线程是并发,进程是并行;进程之间相互独立,是系统分配资源的最小单位,同一个进程中的所有线程共享资源。
进程:一个运行的程序或代码就是一个进程,一个没有运行的代码叫程序。进程是系统进行资源分配的最小单位,进程拥有自己的内存空间,所以进程间数据不共享,开销大。
线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程的存在而存在,一个进程至少有一个线程,叫主线程,多个线程共享内存(数据共享和全局变量),因此提升程序的运行效率。
协程:用户态的轻量级线程,调度有用户控制,拥有自己的寄存器上下文和栈,切换基本没有内核切换的开销,切换灵活。
线程
线程:
- t1 = Thread(target=task1)
- 自定义线程
run()
start()
join()
name: 默认的Thread-1, Thread-2,…
current_thread().name 获取当前线程的名字
is_alive
def task2(n):
for i in range(n):
print('{}劳动最光荣,扫地中...'.format(current_thread().name), i, os.getpid(), os.getppid())
time.sleep(0.5)
if __name__ == '__main__':
print('main:', os.getpid())
# 创建线程对象
t2 = Thread(target=task2,name='小偷', args=(6,))
# 启动线程
t2.start()
# t2.join()
GIL锁(伪线程)
GIL是什么呢?仍然用篮球比赛的例子来帮助理解:把篮球场看作是CPU,一场篮球比赛看作是一个线程,
如果只有一个篮球场,多场比赛要排队进行,就是一个简单的单核多线程的程序;如果有多块篮球场,
多场比赛同时进行,就是一个简单的多核多线程的程序。然而python有着特别的规定:
每场比赛必须要在裁判的监督之下才允许进行,而裁判只有一个。这样不管你有几块篮球场,
同一时间只允许有一个场地进行比赛,其它场地都将被闲置,其它比赛都只能等待。
进程:计算密集型
线程:I/O密集型
Lock
from threading import Lock
lock = Lock()
lock.acquire()握住
lock.release()释放
线程同步异步
线程同步:加锁 一个一个进来,需要排队等待
缺点:效率降低 线程的数据共享 优点:数据是安全的
线程异步:不加锁,execution context 自动从上次保存的地方继续执行