进程、线程、协程、同步与异步

单核CPU实现多任务原理

  • 多任务:多个任务在同一个操作系统上同时运行,这种机制就是多任务。
  • 原理:在这里插入图片描述

多核CPU实现多任务原理

在这里插入图片描述

实现多任务的机制
  • 串行:多个任务依次执行,前面的任务不完成后面的任务不能开启。
  • 并行:多个任务同时执行,他们之间的执行互不影响。并行系统需要有多机支持,多个CPU或者内核或者一个服务器集群。一旦有新的任务产生,这个任务会被分配到一个空闲的处理机上执行。
  • 并发:多个任务以时间片为单位根据特定处理机分配算法来交替执行;例如:一个操作系统中同时打开微信,浏览器,pycharm,并发执行是让微信执行1ns让出cpu,然后浏览器再执行1ns然后让出cpu,然后pycharm再执行1ns让出cpu,然后替换微信,依次轮询下去,在宏观上来看1ns这个时间片人类无法感知。
实现多任务的方式:
1、多进程:启动多个进程,每个进程虽然只有一个线程,但是多个进程可以一起执行多个任务
2、多线程:启动一个进程,在一个进程的内部启动多个线程,这样多个线程也可以一起执行多个任务
3、多进程+多线程:启动多个进程,每个进程中启动多个线程
4、协程:
5、多进程+协程:
进程的概念

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
对于操作系统而言,一个任务就是一个进程。比如打开一个浏览器就是启动一个浏览器进程,在打开一个word,启动一个word进程,如果启动两个word就是启动两个进程

多任务实现技术
  • 多进程
    对于一些比较耗时的操作或者复杂的操作,如果都在同一个进程中执行,这些任务必然把当前进程阻塞,我们可以在主进程中开启一个子进程,让子进程和主进程并发执行。
  • 多线程
    现在在进行程序设计的时候大多采用多线程,进程是操作系统分配资源的基本单位,进程之间资源是相互隔离的(两个进程的资源不共享),进程管理要依赖于操作系统,进程的切换需要不断的分配与回收资源。由于以上的操作多进程机制处理多任务的时候非常麻烦,所以采用多线程来处理;线程是进程的执行子单位,一个进程可以包含若干个线程。
    如果我们进行程序设计时候采用线程机制,程序运行起来以后,操作系统会给程序创建一个进程,给这个进程分配资源(内存和IO),在进程中创建一个主线程,和若干个子线程(也有可能不创建子线程),让这些线程和其他线程或者其他进程去并发的执行
单任务现象
import time
def run1():
   while 1:
       print("tom is a good man")
       time.sleep(1)
def run2():
   while 1:
       print("tom is a nice man")
       time.sleep(1)

if __name__ == "__main__":
   run1()
   # 不会执行run2()方法,只有上面的run1()结束才可执行run2()
   run2()

进程

启动进程实现多任务
from multiprocessing import Process
# 导入进程对象
from time import sleep
import os

def func(string):
   while True:
       print(string)
       print("当前子进程的ID为:",os.getpid())
       sleep(1)

if __name__ == '__main__':
   # func("hello") # 两个任务都在同一个进程中,当前任务不执行完,后面的任务不能开启,这就就是同步
   # 把func中的任务放在子进程中执行
   """"
创建进程(子进程),注意此时进程不会被启动执行
参数target:指定进程执行的任务
参数args:给进函数传递的参数,是一个元组
"""
   p = Process(target=func,args=("我是子进程!",)) # 创建了一个进程,绑定了函数func为它的任务函数
   print(p) # <Process(Process-1, initial)>
   # 开启进程p
   p.start() # p进程开启以后,就会和主进程并发异步执行

# 主进程的结束不能影响子进程,所以可以等待子进程结束在结束主进程
   # 等待子进程结束,才能继续运行主进程
   p.join()


   while True:
       print("我是主进程!我的进程ID为:",os.getpid())
       sleep(1)
主进程负责调度
import time
from multiprocessing import Process

def run1():
    for i in range(5):
        print("tom is a good man")
        time.sleep(1)

def run2(name, word):
    for i in range(8):
        print("%s is a %s man"%(name, word))
        time.sleep(1)


if __name__ == "__main__":
    t1 = time.time()

    # 后期主进程主要做的是调度相关的工作,不负责具体业务逻辑
    pro1 = Process(target=run1, args=())
    pro1.start()
    pro2 = Process(target=run2, args=("kaige", "cool"))
    pro2.start()

全局变量在多个进程中不能共享
import time
from multiprocessing import Process

money = 100

def run1():
   global money #在进程中无法使用全局变量
   money = 200
   for i in range(3):
       time.sleep(1)
   print("run1------money:", money)

def run2():
   money = 300
   for i in range(5):
       time.sleep(1)
   print("run2------money:", money)
if __name__ == "__main__":
   t1 = time.time()

   #在创建子进程时会将主进程的资源拷贝到子进程中,子进程单独有一份主进程中的数据,相互不应响应
   pro1 = Process(target=run1, args=())
   pro2 = Process(target=run2, args=())
   pro1.start()
   pro2.start()
   pro1.join()
   pro2.join()
   print("main-----mony:", money)
   t2 = time.time()
   print("耗时:%2f"%(t2-t1))
#
run1------money: 200
run2------money: 300
main-----mony: 100
耗时:5.170296

如何启动大量子进程
# Pool进程池类
from multiprocessing import Pool
import os
import time
import random

def run(index):
   print("子进程%s启动----进程ID:%s"%(index, os.getpid()))
   t1 = time.time()
   time.sleep(random.random()*5)
   t2 = time.time()
   print("子进程%s结束----进程ID:%s--耗时:%2f" % (index, os.getpid(),t2-t1))

if __name__ == "__main__":
   print("启动主进程")

   #创建进程池对象
   #参数:表示可以同时执行的进程数量
   #由于pool的默认值为CPU核心数,如果有4个核心,则至少需要5个子进程才能看到结果
   pool = Pool(8)
   for i in range(8):
       #创建子进程放入进程池中同一管理
       pool.apply_async(run, args=(i,))


   #进程池对象调用join()之前必须先调用close(),意思是关闭进程池,在调用close()之后就不能再向进程池中添加进程了
   pool.close()
   #pool对象调用join方法,主进程会等待进程池中所有的子进程结束在执行主进程
   pool.join()

   print("结束主进程")

进程间通信
  • 方式:
    有名管道
    无名管道
    队列
    共享内存
    信号
    信号量
  • 生产者消费者模型
from multiprocessing import Process
from multiprocessing import Queue
import time
import random
def product(q):
    print("启动生产子进程……")
    time.sleep(3)
    for data in ["good", "nice", "cool", "handsome"]:
        print("生产出:%s"%data)
        q.put(data)
        time.sleep(random.random()*3)
    print("结束生产子进程……")


def customer(q):
    print("启动消费子进程……")
    while True:
        print("消费者等待数据")
        #获取生产者生产的数据,如果队列中没有数据会阻塞,等队里中有数据在获取
        value = q.get()
        print("消费者消费了%s数据"%(value))
    print("结束消费子进程……")


if __name__ == "__main__":
    #创建消息队列
    q = Queue()
    pro1 = Process(target=product, args=(q,))
    pro2 = Process(target=customer, args=(q,))
    pro1.start()
    pro2.start()
    pro1.join()
    # pro2进程里是死循环,无法等待它的结束
    # pro2.join()
    # 强制结束该子进程
    pro2.terminate()
    print("主进程结束")
单进程实现文件复制
import os
import time
def copyFiles(path, toPath, names):
    for name in names:
        filePath = os.path.join(path, name)
        path2 = os.path.join(toPath, name)

        with open(filePath, "r") as fp1:
            with open(path2, "a") as fp2:
                while True:
                    info = fp1.readline()
                    if info:
                        fp2.write(info)
                        fp2.flush()
                    else:
                        break

if __name__ == "__main__":
    t1 = time.clock()

    path = r"C:\Users\xlg\Desktop\day1903\day18\file1"
    toPath = r"C:\Users\xlg\Desktop\day1903\day18\file2"
    names = ["a1.txt","a2.txt","a3.txt","a4.txt","a5.txt","b1.txt","b2.txt","b3.txt","b4.txt","b5.txt","c1.txt","c2.txt","c3.txt","c4.txt","c5.txt"]

    copyFiles(path, toPath, names)
    t2 = time.clock()
    print("耗时:%.4f"%(t2-t1))
多进程实现文件复制
from multiprocessing import Process
import os
import time

def copyFiles(path, toPath, names):
   for name in names:
       filePath = os.path.join(path, name)
       path2 = os.path.join(toPath, name)

       with open(filePath, "r") as fp1:
           with open(path2, "a") as fp2:
               while True:
                   info = fp1.readline()
                   if info:
                       fp2.write(info)
                       fp2.flush()
                   else:
                       break


if  __name__ == "__main__":
   t1 = time.clock()

   path = r"C:\Users\xlg\Desktop\day1903\day18\file1"
   toPath = r"C:\Users\xlg\Desktop\day1903\day18\file2"
   name1s = ["a1.txt", "a2.txt", "a3.txt", "a4.txt", "a5.txt"]
   name2s = ["b1.txt", "b2.txt", "b3.txt", "b4.txt", "b5.txt"]
   name3s = ["c1.txt", "c2.txt", "c3.txt", "c4.txt", "c5.txt"]
   pro1 = Process(target=copyFiles, args=(path, toPath, name1s))
   pro2 = Process(target=copyFiles, args=(path, toPath, name2s))
   pro3 = Process(target=copyFiles, args=(path, toPath, name3s))
   pro1.start()
   pro2.start()
   pro3.start()

   pro1.join()
   pro2.join()
   pro3.join()

   t2 = time.clock()
   print("耗时:%.4f"%(t2-t1))
封装进程子类
from multiprocessing import Process

class RunProcess(Process):
    def __init__(self, name="pro"):
        super().__init__()
        self.name = name
    # 当对象调用start方法时,默认调用run方法
    def run(self):
        print("启动子进程(%s)"%(self.name))
        print("结束子进程(%s)" % (self.name))

#另一个模块
from runProcess import RunProcess

if __name__ == "__main__":
    pro = RunProcess(name="abcd")
    pro.start()
    pro.join()

多线程

  • 线程
    是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程
  • 多线程
    是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。 [1] 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能
启动线程实现多任务

_thread模块:低级模块
threading模块:高级模块,对_thread进行了封装

import threading
from time import sleep
import _thread # 用于以守护的方式给主线程开启一个子线程

# 定义一个函数,用于绑定子线程的任务
def func(string):
    name = threading.current_thread().name
    print("当前线程为:",name)
    for i in range(1,9):
        print("当前线程%s执行了第%d次循环!"%(name,i))
        sleep(2)

# 方式一:守护线程
def thread1():
    # 给当前主线程开启一个守护子线程
    _thread.start_new_thread(func,("mm",)) # 守护线程的依赖于主线程,主线程存在它才有可能存在,主线程死掉守护线程也会死掉
    print("我是主线程:",threading.current_thread().name)
    for i in range(1,9):
        print("线程%s执行了第%d次循环"%(threading.current_thread().name,i))
        sleep(1)
# 方式二:非守护线程
def thread2():
    # 以非守护的方式创建一个线程
    t1 = threading.Thread(target=func,args=("mm",))
    # 开启线程
    t1.start() # 一旦开启,子线程和主线程没有任何关系,只是并发执行,主线程死掉和子线程无关
    print("我是主线程:", threading.current_thread().name)
    for i in range(1, 9):
        print("线程%s执行了第%d次循环" % (threading.current_thread().name, i))
        sleep(1)

# 方式三:自定义线程
# 自定义一个线程对象
class MyThread(threading.Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    # 重写Thread的run方法,来重新定义线程的功能
    def run(self):
        print("当前线程为:", self.name)
        for i in range(1, 9):
            print("线程%s执行了第%d次循环" % (self.name, i))
            sleep(2)

def thread3():
    # 创建自定义的线程对象
    t = MyThread(name="老王线程")
    t.start()
    print("我是主线程:", threading.current_thread().name)
    for i in range(1, 9):
        print("线程%s执行了第%d次循环" % (threading.current_thread().name, i))
        sleep(1)



if __name__ == '__main__':
    thread3()

线程间共享数据

#多线程和多进程最大的不同在于,多进程中,同一个全局变量,每个子进程各自有一份拷贝,相互不影响。而在多线程中,所有变量都由线程所共享。因此,多个线程同时改变一个变量容易内存错乱

import threading
money = 0

def changeMoney(n):
   global money
   money += n
   money -= n

def run1():


   for i in range(1000):
       changeMoney(5)

def run2():


   for i in range(1000):
       changeMoney(9)

if __name__ == "__main__":
   th1 = threading.Thread(target=run1)
   th2 = threading.Thread(target=run2)
   th1.start()
   th2.start()
   th1.join()
   th2.join()

   print("main-----", money)
线程锁解决数据紊乱
import threading

#问题:两个线程同时一寸一取,可能造成变量值的不对,我们必须保证一个线程在修改money时,其他的线程一定不能修改

money = 0

#锁对象
lock = threading.Lock()
#后期在线程中对变量上锁,但是千万要注意释放锁(自己的锁自己释放),否则会造成死锁

def changeMoney(n):
   global money
   money += n
   money -= n

def run1():
   for i in range(1000000):
       #获取线程锁,如果已上锁,则阻塞等待锁的释放
       lock.acquire()
       try:
           changeMoney(5)
       finally:
           #释放锁
           lock.release()


def run2():
   for i in range(1000000):
       #简写,与上面功能一致
       with lock:
           changeMoney(9)

if __name__ == "__main__":
   th1 = threading.Thread(target=run1)
   th2 = threading.Thread(target=run2)
   th1.start()
   th2.start()
   th1.join()
   th2.join()

   print("main-----", money)
threadLocal 对象解决紊乱

import threading
import time


#得到一个ThreadLocal对象,可以为每个线程提供独立的存储空间,每个线程对它都可以进行读写操作,但是相互不影响
local = threading.local()

def run1():
    local.money = 1
    time.sleep(4)
    print("run1------1-", local.money)


def run2():
    time.sleep(2)
    local.money = 2
    time.sleep(4)
    print("run2-----1-", local.money)

if __name__ == "__main__":
    th1 = threading.Thread(target=run1)
    th2 = threading.Thread(target=run2)
    th1.start()
    th2.start()
    th1.join()
    th2.join()


多线程实现文件复制
import threading
import os
import time

lock = threading.Lock()

names = ["a1.txt","a2.txt","a3.txt","a4.txt","a5.txt","b1.txt","b2.txt","b3.txt","b4.txt","b5.txt","c1.txt","c2.txt","c3.txt","c4.txt","c5.txt"]

def copyFiles(path, toPath):
    print('--------------', threading.current_thread().name)
    global names
    while len(names):
        with lock:
            name = names.pop()
        filePath = os.path.join(path, name)
        path2 = os.path.join(toPath, name)
        with open(filePath, "r") as fp1:
            with open(path2, "a") as fp2:
                while True:
                    info = fp1.readline()
                    if info:
                        fp2.write(info)
                        fp2.flush()
                    else:
                        break

if  __name__ == "__main__":
    t1 = time.clock()

    path = r"C:\Users\xlg\Desktop\day1903\day18\file1"
    toPath = r"C:\Users\xlg\Desktop\day1903\day18\file2"
    th1 = threading.Thread(target=copyFiles, args=(path, toPath))
    th2 = threading.Thread(target=copyFiles, args=(path, toPath))
    th3 = threading.Thread(target=copyFiles, args=(path, toPath))
    th1.start()
    th2.start()
    th3.start()

    th1.join()
    th2.join()
    th3.join()

    t2 = time.clock()
    print("耗时:%.4f"%(t2-t1))
信号量
# 信号量
# 信号量就是对线程的最大并发量做限制,如果当前并发量超过了信号量,则超出的那些线程要暂停执行,而当有线程执行结束,暂停的线程才能开启
import threading
from time import sleep
# 定义一个信号量(线程的最大并发量)
sem = threading.Semaphore(3)
def func():
    with sem:
        # 在线程任务上加入信号量
        print("当前线程%s正在执行..."%threading.current_thread().name)
        sleep(2)
        print("当前线程%s执行结束!"%threading.current_thread().name)
if __name__ == '__main__':
    for _ in range(10):
        t = threading.Thread(target=func)
        t.start()

封装线程子类
import threading

class RunThread(threading.Thread):
    def __init__(self):
        super().__init__()
    # 当对象调用start方法时,默认调用run方法
    def run(self):
        print("启动子线程")
        print("结束子线程")

#另一个模块
from runThread import RunThread

if __name__ == "__main__":
    th = RunThread()
    th.start()
    th.join()

进程和线程的 对比

在这里插入图片描述

协程

  • 子程序:在所有的语言中都是层级调用,比如A中调用B,B在执行过程中调用C,C执行完返回,B执行完返回,最后是A执行完毕。是通过栈实现的,一个线程就是执行一个子程序,子程序的调用总是有一个入口,一次返回,调用的顺序是明确的

  • 协程:又称微线程(纤程),是一种用户态的轻量级线程

  • 理解协程:
    1、普通理解:线程是系统级别的,他们是有操作系统调度。协程是程序级别的,由程序员根据需求自己调度。我们把一个线程中的一个个函数称为子程序,那么一个子程序在执行的过程中可以中断去执行别的子程序,这就是协程。也就是说同一个线程下的一段代码1执行执行着就中断,然后去执行另一段代码2,当再次回来执行代码1的时候,接着从之前中断的地方开始执行
    2、专业理解:协程拥有自己的寄存器上下文和栈,协程在调度切换时,将寄存器上下文和栈保存到其他的地方,在切换回来时,恢复先前保存的寄存器上下文和栈。因此,协程能保留一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

  • 优点:
    1、无需线程上下文切换的开销,协程避免了无意义的调度,由此提高了性能,但是程序员必须自己承担调度的任务,同时协程页也失去了标准线程使用多CPU的能力
    2、无需原子操作锁定及同步的开销
    3、方便切换控制流,简化编程模型
    4、高并发+高扩展性+低成本,一个CPU支持上万个协程不是问题

  • 缺点:
    1、无法利用多核CPU资源,协程的本质是单个线程,它不能同时将多个CPU的多个核心使用上,协程需要和进程匹配使用才能运行在多CPU上。但是一般不需要,除非是CPU计算密集型的应用
    2、进行阻塞操作(操作IO)会阻塞整个程序

  • 发展历史:
    1、最初的生成器变形yield/send
    2、引入@asyncio.coroutine和yield from
    3、在最近的python3.5版本中引入async/await关键字

协程的数据传递

def func():
    data = "#"
    print("----------------1")
    r = yield data
    print("----------------2", r)
    r = yield data
    print("----------------3", r)
    r = yield data
    print("----------------4", r)
    r = yield data

g = func()
# print(g, type(g))
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))

#启动g,从第二个开始send的值会放到yield处
print(g.send(None))
print(g.send("a"))
print(g.send("b"))
print(g.send("c"))


#
----------------1
#
----------------2 a
#
----------------3 b
#
----------------4 c
#

协程实现生产者和消费者

import time
import random
def product(c):
    print("启动生产者……")
    #启动消费者
    c.send(None)
    for data in ["good", "nice", "cool"]:
        print("生产出:%s"%data)
        #消费者生成器.send()
        c.send(data)
        time.sleep(3)
    #关闭消费之
    c.close()
    print("结束生成者……")

def customer():
    print("启动消费者……")
    while True:
        print("消费者等待数据")
        #获取数据
        value = yield
        print("消费者消费了%s数据" % (value))

c = customer()
product(c)

同步与异步

  • 概述:python由于GIL(全局锁)的存在,不能发挥多核优势,其性能一直被人诟病。然而在IO密集型的网络编程里,异步处理比同步处理性能会提升成千上百倍
  • 同步:指完成事物的逻辑,先执行第一个事物,如果阻塞了,会一直等待,直到这个事物完成,在执行第二个事物,顺序执行
  • 异步:是和同步相对的,指在处理调用这个事物之后,不会等待这个事物的处理结果,直接去处理第二个事物。通过状态、通知、回调来通知调用者处理结果

异步代码

import asyncio
import time

# 定义异步函数(定义一个协程)
async def func():
    print("tom is a good man")
    #模拟一个耗时IO操作
    asyncio.sleep(2)
    print("tom is a very good man")

loop = asyncio.get_event_loop()
for i in range(5):
    loop.run_until_complete(func())

while 1:
    time.sleep(1)

asyncio模块

asyncio模块是python3.4版本引入标准库,直接内置了对异步IO的操作

  • 编程模式:是一个消息循环,我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步

  • 说明:到目前为止实现协程的不仅只有asyncio,还有gevent和tornado都是实现了类似的功能

  • 关键字说明:
    1、event_loop(事件循环):程序开启一个无限循环,把一个函数注册到事件循环中,当满足条件发生时,调用相应的协程函数
    2、coroutine(协程):协程对象,值一个使用async关键字定义的函数,它的调用不会立即执行函数,而会返回一个协程对象。协程对象需要注册到事件循环中,由事件循环调用
    3、task(任务):一个协程对象就是一个原生可以挂起的函数,任务则是对协程进行一步的封装,其中包含了任务的各种状态
    4、future:代表执将来执行或没没有执行的任务的结果,它和task上没有本质的区别
    5、async/await:python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞异步调用接口

定义一个协程
import asyncio
import time

#通过async关键字定义一个协程,协程不能直接运行,需要将协程加入到事件循环中
async def run(x):
  print("waiting:%d"%x)

#得到一个协程对象
coroutine = run(2)
# print(coroutine)


t1 = time.clock()

#创建一个事件循环
#注意:真实情况是在asyncio模块中获取一个引用
loop = asyncio.get_event_loop()

#将协程对象加入到事件循环
loop.run_until_complete(coroutine)

t2 = time.clock()
print("Time:%.4f"%(t2-t1))
创建一个任务

import asyncio
import time

async def run(x):
    print("waiting:%d"%x)

t1 = time.clock()

coroutine = run(2)

loop = asyncio.get_event_loop()
#协程对象加入到事件循环中,协程对象不能直接运行,在注册事件循环时,其实是run_until_complete()方法加协程对象包装成一个任务,task对象是Future类子类对象,保存协程运行后的状态,用于未来获取协程的结果
# loop.run_until_complete(coroutine)

# 创建任务
task = asyncio.ensure_future(coroutine)
# 将任务加入事件循环
loop.run_until_complete(task)

t2 = time.clock()
print("Time:%.4f"%(t2-t1))
绑定回调

import asyncio
import time
async def run(x):
    print("waiting:%d"%x)
    #向百度要数据,网络IO
    asyncio.sleep(10)
    print("end run")
    return "sunck is a good man"

def callBack(future):
    print("callback:", future.result())

t1 = time.clock()

coroutine = run(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
#给任务添加回调,在任务结束后调用回调函数
task.add_done_callback(callBack)
loop.run_until_complete(task)

t2 = time.clock()
print("Time:%.4f"%(t2-t1))



while 1:
    time.sleep(5)

回调函数
import time
import asyncio

def callback(future):
    print("callback:", future.result())

# def longIO():
#     time.sleep(6)
#     return "sunck is a good man"

async def getBaidu():
    print("开始请求百度……")
    #请求的代码
    #异步请求数据
    print("请求百度已发送")
    return "百度数据"
async def getXinlang():
    print("开始请求新浪……")
    #请求的代码
    time.sleep(4)
    print("请求新浪已发送")
    return "新浪数据"

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    task1 = asyncio.ensure_future(getBaidu())
    task2 = asyncio.ensure_future(getXinlang())

    #添加回调
    task1.add_done_callback(callback)
    task2.add_done_callback(callback)

    print("向百度要数据")
    loop.run_until_complete(task1)


    print("向新浪要数据")
    loop.run_until_complete(task2)
阻塞和await

'''
async可以定义协程对象,使用await可以针对耗时的操作进行挂起,就与生成新的yield一样,函数交出控制权。协程遇到await,事件循环将会挂起该协程,执行别的协程,直到其他协程也会挂起或者执行完毕,在进行下一个下次的执行
'''
import time
import asyncio

def callback(future):
    print("callback:", future.result())

# def longIO():
#     time.sleep(5)
#     return "sunck is a good man"

async def getBaidu():
    print("开始请求百度……")
    #请求的代码
    #异步请求数据
    await asyncio.sleep(5)
    print("请求百度已发送")
    return "百度数据"

# async def getXinlang():
#     print("开始请求新浪……")
#     #请求的代码
#     asyncio.sleep(3)
#     print("请求新浪已发送")
#     return "新浪数据"

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    task1 = asyncio.ensure_future(getBaidu())
    # task2 = asyncio.ensure_future(getXinlang())

    #添加回调
    task1.add_done_callback(callback)
    # task2.add_done_callback(callback)

    print("向百度要数据")
    loop.run_until_complete(task1)


    # print("向新浪要数据")
    # loop.run_until_complete(task2)
并行和并发
'''
并发:指任务数大于核心数

并行:任务数小于等于核心数

并发类似于一个老师在同一时段辅导不同的学生功课,并行好几个老师分别辅导不同的学生
'''

import time
import asyncio
import random

def callback(future):
    print("callback:", future.result())

async def getHtml(home):
    print("开始请求%s……"%home)
    #请求的代码
    #异步请求数据
    await asyncio.sleep(5)
    return "%s数据"%home



if __name__ == "__main__":
    con1 = getHtml("百度")
    con2 = getHtml("阿里")
    con3 = getHtml("腾讯")

    task1 = asyncio.ensure_future(con1)
    task2 = asyncio.ensure_future(con2)
    task3 = asyncio.ensure_future(con3)
    task1.add_done_callback(callback)
    task2.add_done_callback(callback)
    task3.add_done_callback(callback)
    tasks = [task1, task2, task3]

    loop = asyncio.get_event_loop()

    t1 = time.clock()
    loop.run_until_complete(asyncio.gather(*tasks))
    # loop.run_until_complete(asyncio.gather(task1, task2, task3))
    # loop.run_until_complete(task1)
    # loop.run_until_complete(task2)
    # loop.run_until_complete(task3)
    t2 = time.clock()
    print("耗时:%.4f"%(t2-t1))
协程的嵌套

'''
并发:指任务数大于核心数

并行:任务数小于等于核心数

并发类似于一个老师在同一时段辅导不同的学生功课,并行好几个老师分别辅导不同的学生
'''


import time
import asyncio
import random

def callback(future):
    print("callback:", future.result())

async def getHtml(home):
    print("开始请求%s……"%home)
    await asyncio.sleep(5)
    return "%s数据"%home


async def main():
    con1 = getHtml("百度")
    con2 = getHtml("阿里")
    con3 = getHtml("腾讯")

    task1 = asyncio.ensure_future(con1)
    task2 = asyncio.ensure_future(con2)
    task3 = asyncio.ensure_future(con3)
    # task1.add_done_callback(callback)
    # task2.add_done_callback(callback)
    # task3.add_done_callback(callback)
    tasks = [task1, task2, task3]

    #1、
    # dones, pendings = await asyncio.wait(tasks)
    # for task in dones:
    #     print("task返回值:", task.result())

    #2、
    # resultss = await asyncio.gather(*tasks)
    # for result in results:
    #     print("task 返回值:", result)


    #3、
    # return await asyncio.wait(tasks)

    # 4、
    # return await asyncio.gather(*tasks)

    # 5、
    for task in asyncio.as_completed(tasks):
        result = await task
        print("task 返回值:", result)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    t1 = time.clock()

    # 1、
    # loop.run_until_complete(main())

    # 2、
    # loop.run_until_complete(main())

    # 3、
    # dones, pendings = loop.run_until_complete(main())
    # for task in dones:
    #     print("task返回值:", task.result())

    # 4、
    # results = loop.run_until_complete(main())
    # for result in results:
    #     print("task 返回值:",result)


    # 5、
    loop.run_until_complete(main())

    t2 = time.clock()
    print("耗时:%.4f"%(t2-t1))

不同线程换的事件循环

'''
一般情况我们的事件循环用于注册协程,有一些协程需要动态的添加到事件循环中。简单的方式就是使用多线程,当前线程创建一个事件循环,然后开启一个新线程,在新线程中启动事件循环,当前线程不会被阻塞
'''
import threading
import asyncio
import time

def start_loop(loop):
    #启动事件循环
    asyncio.set_event_loop(loop)
    loop.run_forever()

def run(x):
    print("sunck is a good man", x)
    time.sleep(x)
    print("sunck is a very good man", x)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    #创建新的线程,用于启动事件循环,此时不会阻塞主线程
    threading.Thread(target=start_loop, args=(loop,)).start()

    #给事件循环添加任务
    loop.call_soon_threadsafe(run, 4)
    loop.call_soon_threadsafe(run, 6)

新线程协程

'''
一般情况我们的事件循环用于注册协程,有一些协程需要动态的添加到事件循环中。
简单的方式就是使用多线程,当前线程创建一个事件循环,然后开启一个新线程,在新线程中启动事件循环
,当前线程不会被阻塞
'''
import threading
import asyncio
import time

def start_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()

async def run(x):
    print("tom is a good man", x)
    await asyncio.sleep(x)
    print("tom is a very good man", x)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    #创建新的线程,用于启动事件循环,此时不会阻塞主线程
    threading.Thread(target=start_loop, args=(loop,)).start()

    #给事件循环添加任务
    asyncio.run_coroutine_threadsafe(run(4), loop)
    asyncio.run_coroutine_threadsafe(run(6), loop)

异步获取网页信息

import threading
import asyncio

def start_loop(lp):
    asyncio.set_event_loop(lp)
    lp.run_forever()

async def getHtml(url):
    print("开始加载%s网址"%url)
    connet = asyncio.open_connection(url, 80)
    print(connet)
    reader, writer = await connet
    #链接成功
    header = "GET / HTTP/1.0\r\nHost: %s\r\n\r\n"%(url)
    writer.write(header.encode("utf-8"))
    await writer.drain()

    #接收数据
    while True:
        line = await reader.readline()
        if line == b'\r\n':
            break
        print("%s header--%s"%(url, line.decode("utf--8")))
    writer.close()


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    threading.Thread(target=start_loop, args=(loop,)).start()

    urls = ["www.baidu.com", "www.163.com","www.sina.com.cn"]

    for url in urls:
        asyncio.run_coroutine_threadsafe(getHtml(url), loop)

await 后面的函数

'''
一般情况我们的事件循环用于注册协程,有一些协程需要动态的添加到事件循环中。简单的方式就是使用多线程,当前线程创建一个事件循环,然后开启一个新线程,在新线程中启动事件循环,当前线程不会被阻塞
'''
import threading
import asyncio
import time

def start_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()

def longIO():
    print("--------------1")
    for i in range(5):
        print("***********", i)
        time.sleep(1)
    print("--------------2")
    return "info"


async def run(x):
    print("sunck is a good man", x)
    await longIO()
    print("sunck is a very good man", x)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    threading.Thread(target=start_loop, args=(loop,)).start()
    asyncio.run_coroutine_threadsafe(run(4), loop)
    asyncio.run_coroutine_threadsafe(run(6), loop)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值