看到吐血 _(´ཀ`」 ∠)_

  • 协程(Coroutine)本质上是一个函数,特点是在代码块中可以将执行权交给其他协程
  • 众所周知,子程序(函数)都是层级调用的,如果在A中调用了B,那么B执行完毕返回后A才能执行完毕。协程与子程序有点类似,但是它在执行过程中可以中断,转而执行其他的协程,在适当的时候再回来继续执行。
  • 协程与多线程相比的最大优势在于:协程是一个线程中执行,没有线程切换的开销
  • 这里用到的是asyncio库(Python 3.7),这个库包含了大部分实现协程的魔法工具
    • 使用 async 修饰词声明异步函数
    • 使用 await 修饰词调用异步函数
    • 使用 asyncio.create_task 创建任务

解析协程运行时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import asyncio
import time

async def a():
print("欢迎使用 a !")
await asyncio.sleep(1)
print("欢迎回到 a !")

async def b():
print("欢迎来到 b !")
await asyncio.sleep(2)
print("欢迎回到 b !")

async def main():
task1 = asyncio.create_task(a())
task2 = asyncio.create_task(b())
print("准备开始")
await task1
print("task1 结束")
await task2
print("task2 结束")

if __name__ == "__main__":
start = time.perf_counter()

asyncio.run(main())

print('花费 {} s'.format(time.perf_counter() - start))

运行结果

  • 解释:
    • 1、asyncio.run(main()),程序进入main()函数,开启事件循环
    • 2、创建任务task1、task2并进入事件循环等待运行
    • 3、输出准备开始
    • 4、执行await task1,用户选择从当前主任务中切出,事件调度器开始调度 a
    • 5、a 开始运行,输出欢迎使用a!,运行到await asyncio.sleep(1),从当前任务切出,事件调度器开始调度 b
    • 6、b 开始运行,输出欢迎来到b!,运行到await asyncio.sleep(2),从当前任务切出
    • 7、以上事件运行时间非常短(毫秒),事件调度器开始暂停调度
    • 8、一秒钟后,a的sleep完成,事件调度器将控制权重新交给a,输出欢迎回到a!,task1完成任务,退出事件循环
    • 9、await task1完成,事件调度器将控制权还给主任务,输出task1结束,然后在await task2处继续等待
    • 10、两秒钟后,b的sleep完成,事件调度器将控制权重新传给 b,输出欢迎回到 b!,task2完成任务,从事件循环中退出
    • 11、事件调度器将控制权交还给主任务,主任务输出task2结束,至此协程任务全部结束,事件循环结束。

异步接口同步实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"""
- 简单爬虫模拟
- 这里用异步接口写了个同步代码
"""

import asyncio
import time

async def crawl_page(url):
print('crawling {}'.format(url))
sleep_time = int(url.split('_')[-1])
await asyncio.sleep(sleep_time) # 休眠
print('OK {}'.format(url))

async def main(urls):
for url in urls:
await crawl_page(url) # await会将程序阻塞在这里,进入被调用的协程函数,执行完毕后再继续


start = time.perf_counter()

# pip install nest-asyncio
asyncio.run(main(['url_1', 'url_2'])) # 协程接口

print("Cost {} s".format(time.perf_counter() - start))

使用Task实现异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 异步实现

import asyncio
import time

async def crawl_page(url):
print('crawling {}'.format(url))
sleep_time = int(url.split('_')[-1])
await asyncio.sleep(sleep_time)
print('OK {}'.format(url))

async def main(urls):
tasks = [asyncio.create_task(crawl_page(url)) for url in urls]
for task in tasks:
await task
# 14、15行也可以换成这一行await asyncio.gather(*tasks)
# *tasks 解包列表,将列表变成了函数的参数,与之对应的是,** dict 将字典变成了函数的参数

start = time.perf_counter()

asyncio.run(main(['url_1', 'url_2']))

print("Cost {} s".format(time.perf_counter() - start))

  • 对象:一个自包含的实体,用一组可识别的特性和行为来标识
  • 类:具有相同的属性和功能的对象的抽象的集合
  • 实例:一个真实的对象,实例化就是创建对象的过程
  • 多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常运行
  • 封装:对外部隐藏有关对象工作原理的细节
  • 继承:可基于通用类创建专用类

多态

  • 多态可以让我们在不知道变量指向哪种对象时,也能够对其执行操作,且操作的行为将随对象所属的类型(类)而异。每当不知道对象是什么样就能对其执行操作,都是多态在起作用
  • 多态以 继承 和 重写 父类方法 为前提
  • 多态是调用方法的技巧,不会影响到类的内部设计
  • 多态性即向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)
  • 听说Python天然就多态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Person(object):
def __init__(self,name,sex):
self.name = name
self.sex = sex

def print_title(self):
if self.sex == "male":
print("man")
elif self.sex == "female":
print("woman")

class Child(Person): # Child 继承 Person
def print_title(self):
if self.sex == "male":
print("boy")
elif self.sex == "female":
print("girl")

May = Child("May","female")
Peter = Person("Peter","male")

print(May.name,May.sex,Peter.name,Peter.sex)
# 同一消息
May.print_title()
Peter.print_title()

玩Python这么久了,连Jupyter都不会,有点捞,今天补一补这方面的操作。。。。

Jupyter Notebooks

  Jupyter Notebooks 是一款开源的网络应用,我们可以将其用于创建和共享代码与文档。其提供了一个环境,你无需离开这个环境,就可以在其中编写你的代码、运行代码、查看输出、可视化数据并查看结果。因此,这是一款可执行端到端的数据科学工作流程的便捷工具,其中包括数据清理、统计建模、构建和训练机器学习模型、可视化数据等等。

安装

pip install ipython jupyter

上手上手

在终端输入jupyter notebook启动Jupyter notebooks,它会在默认浏览器中打开,地址是http://localhost:8888/tree。

VCCz7R.md.png

进程 && 线程

进程:进程是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间,每个进程都有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据,操作系统管理所有进程的执行,为它们合理的分配资源。进程可以通过fork或者wpawn的方式来创建新的进程执行其他任务,不过新的进程有自己独立的内存空间和数据栈,所以必须通过进程间的通信机制(IPC,Inter Process Communication)来实现数据共享,具体的方式包括管道、信号、套接字、共享内存等。

线程:进程的一个执行单元。线程在同一个进程中执行,共享程序的上下文。一个进程中的各个线程与主线程共享同一片数据空间,因而相比与独立的进程,线程间的信息共享和通信更为容易。线程一般是以并发的方式执行的。注意在单核CPU系统中,真正的并发是不可能的,所以新城的执行实际上是这样规划的:每个线程执行一小会,然后让步给其他线程的任务(再次排队等候更多的CPU执行时间)。在整个线程的执行过程中,每个线程执行它自己的特定的任务,在必要时和其他进程进行结果通信。

Python多进程(使用multiprocessing)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from time import time, sleep
from random import randint
from multiprocessing import Process

def my_task(name):
sleep_time = randint(1,10)
sleep(sleep_time)
print("你叫了一声%s,它鸟你用了%d秒" % (name, sleep_time))


def main():
start = time()
process_1 = Process(target=my_task, args=["yeshan", ])
process_2 = Process(target=my_task, args=["foel", ])
# 启动进程
process_1.start()
process_2.start()
# 等待进程执行结束
process_1.join()
process_2.join()
end = time()
print("一共花费了%f秒" % (end-start))


if __name__ == '__main__':
main()

让vscode使用Pipenv工作环境

1、查看Pipenv的位置

1
2
3
4
# 先激活Pipenv环境
pipenv shell
# 获取当前虚拟环境的位置
pipenv --venv

2、打开setting.json配置文件

  • Ctrl+Shift+P,输入settings,选择Open Settings(JSon)
  • 将之前得到的Pipenv环境路径添加进去

    “python.venvPath”: “C:\\Users\\Algorithm\.virtualenvs”

python生成器(generator)

  • 生成器是一种使用普通函数语法定义的迭代器
  • 包含yield语句的函数都是生成器,它是一个不断产生值的函数
  • 生成器每次使用yield产生一个值后,函数都将冻结,即在此处停止执行,等待重新被唤醒。被唤醒后从停止的地方开始继续执行

生成器推导(生成器表达式)

使用圆括号()创建一个生成器推导 ,它创建了一个可迭代的对象
使用next()函数可以获得生成器推导的下一个返回值

g = (i**2 for i in range(10))


博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Material X 作为主题 , 总访问量为 次 。