day39

今日内容:

1.异步同步 和 阻塞非阻塞 概念 ******

2.异步回调 ******

    为什么需要回调

      子进程帮助主进程完成任务 处理任务的结果应该是、交给准进程

    其他方式也可以将数据交还给主进程

       1.shutdown 主进程会等所有任务完成

       2.result函数 会阻塞直到完成任务

        都会阻塞 导致效率降低 所以使用回调

   注意:

          回调函数什么时候被执行? 子进程完成时

          谁在执行回调函数? 主进程

   线程的异步回调

           使用方式都相同 唯一不同的是执行回调函数 是子进程在执行

3.线程列队 ****

     列队

     堆栈

     优先级列队

4.协程

     协程的目的是在单线程下实现并发

     为什么出现协程?因为cpython由于GIL 导致同一时间只有一个线程再跑

         意味着 如果你的线程序计算密集 多线程效率也不会提升

         如果是io密集型 有没有必要再单线程下实现并发 

         没有 我还开启多线程来处理io 子线程遇到io cpu切走 但是请问 你能保证一定切换到主线程吗? 不能保证

      有 如果可以 我在遇到io的时候转而去做计算 这样一来可以保证cpu一直在处理你的程序 当然时间太长也会切换

      总结:单线程下实现并发 将io阻塞时间用于执行计算 可以提高效率 原理:一直使用cpu直到超时

怎么实现单线程并发?

    并发 指的是 看起来像是同时运行 实际上是在任务之间来回切换 同时需要保存执行的状态

    任务一堆代码 可以用函数装起来

     1.如何让两个函数切换执行

        yield可以保存函数的执行状态

        通过生成器还有实现为并发

        并发不一定提升效率 反而会降低效率 当任务全是计算时

       2.如何知道发生了io?从而切换执行

            目前咱们实现不了

   第三方模块 greenlet 可以实现并发 但是不能检测io

   第三方模块gevent 封装greenlet 可以实现单线程并发 并且可以检测io操作 自动切换

同步异步:

 线程的三种状态:

    1.就绪

    2.运行

    3.阻塞

 阻塞 遇到了io操作 代码卡住 无法执行下一行 CPU会切换的其他任务

 

 非阻塞 雨阻塞相反 代码正在执行(运行状态)或者处于就绪状态

 阻塞和非阻塞描述的是运行的状态

 同步:提交任务必须等待任务完成 才能执行下一行

 异步:提交任务不需要等待任务完成立即执行下一行

 指的是一种提交任务的方式

def task():
    for i in range(1000000):
        i += 1000
    print("11111")

print("start")
task() # 同步提交方式
print("end")

from threading import  Thread

print("start1")
Thread(target=task).start()  # 异步提交
print("end1")

2.利用回调完成生产者消费:

 

from  concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import current_thread
import  os
pool = ThreadPoolExecutor()

# 爬虫  1.从网络某个地址获取一个HTML文件

import requests # 该模块用于网络(HTTP)请求

# 生产数据
def get_data_task(url):
    print(os.getpid(),"正在生产数据!")
    # print(current_thread(),"正在生产数据!")

    response = requests.get(url)
    text = response.content.decode("utf-8")
    print(text)
    return text


#   处理数据
def parser_data(f):
    print(os.getpid(),"处理数据")
    # print(current_thread(), "处理数据")
    print("正在解析: 长度%s" % len(f.result()))


urls = [
    "http://www.baidu.com",
    "http://www.baidu.com",
    "http://www.baidu.com",
    "http://www.baidu.com"
]

if __name__ == '__main__':
    for url in urls:
        f = pool.submit(get_data_task,url)
        f.add_done_callback(parser_data)  # 回调函数是主进程在执行
        # 因为子进程是负责获取数据的  然而数据怎么处理 子进程并不知道  应该把数据还给主进程
    print("over")

3.线程队列:

import queue

# 普通队列 先进先出
q = queue.Queue()
q.put("a")
q.put("b")


print(q.get())
print(q.get())

# 堆栈队列  先进后出 后进先出  函数调用就是进栈  函数结束就出栈 递归造成栈溢出
q2 = queue.LifoQueue()
q2.put("a")
q2.put("b")
print(q2.get())


# 优先级队列
q3 = queue.PriorityQueue()  # 数值越小优先级越高  优先级相同时 比较大小 小的先取
q3.put((-100,"c"))
q3.put((1,"a"))
q3.put((100,"b"))
print(q3.get())

4.协程实现:

mport time
def task():
    while True:
        print("task1")
        time.sleep(4)
        yield 1


def task2():
    g = task()
    while True:
        try:
            print("task2")
            next(g)
        except Exception:
            print("任务完成")
            break
task2()

5.greenlet使用:

 

import greenlet

import time
def task1():
    print("task1 1")
    time.sleep(2)
    g2.switch()
    print("task1 2")
    g2.switch()

def task2():
    print("task2 1")
    g1.switch()
    print("task2 2")

g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)

g1.switch()

1.实例化greenlet得到一对象 传入要执行的任务

  至少需要两个任务

2.先让某一个任务执行起来 使用对象调用switch

3.在任务的执行过程中 手动调用switch来切换

6.gevent使用:

from gevent import monkey
monkey.patch_all()

import gevent
import time
def eat():
    print('eat food 1')
    time.sleep(2)
    # gevent.sleep(1)
    print('eat food 2')

def play():
    print('play 1')
    time.sleep(1)
    # gevent.sleep(1)
    print('play 2')

g1=gevent.spawn(eat)
g2=gevent.spawn(play)
# g1.join()
# g2.join()

gevent.joinall([g1,g2])
print('')

1.spawn函数传入你的任务

2.调用join 去开启任务

3.检测io操作需要打开monkey补丁 就是一个函数 在程序最开始的地方调用它

     

 

转载于:https://www.cnblogs.com/hui2002/p/9954811.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值