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

简单了解线程和协程(C#) 阅读详情

单核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)
一次性搞懂同步、异步、阻塞、非阻塞、进程、线程、协程、并发、并行 回调是异步操作完成后,用于通知调用者的函数。事件循环是一个不断检查并处理事件的无限循环,是Node.js、浏览器等单线程异步系统的核心。场景推荐方案理由CPU密集型任务多进程/多线程需要真正的并行计算IO密集型任务(高并发)IO多路复用(epoll)+协程单线程处理大量连接IO密集型任务(极致性能)io_uring(真异步)零拷贝,内核异步处理简单脚本工具同步阻塞代码简单,够用就好高性能服务器事件循环+IO多路复用+线程池结合多种技术Web后端协程+IO多路复用。 阅读详情

相关推荐

C#中更强大的协程实现——.NET

在C#中,.NET框架提供了Task和async/await模式来处理异步操作,但有时候我们需要更高级的协程功能来管理复杂的异步流程。总结起来,C#中的协程是一种强大的并发编程模型,可以简化异步代码的编写和管理。通过使用第三方库AsyncEnumerable,我们可以实现更强大的协程功能,并以一种直观、简洁的方式处理复杂的异步流程。通过使用AsyncEnumerable库,我们可以以一种更直观、简洁的方式编写复杂的异步代码。在这里,我们将介绍使用第三方库AsyncEnumerable来实现协程功能的方法。

RzuScala的博客 843

归纳一下:C#线程同步的几种方法

  我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在后台处理一大堆数据,但还要使用户界面处于可操作状态;或者你的程序需要访问一些外部资源如数据库或网络文件等。这些情况你都可以创建一个子线程去处理,然而,多线程不可避免地会带来一个问题,就是线程同步的问题。如果这个问题处理不好,我们就会得到一些非预期的结果。   在网上也看过一些关于线程同步的文章,其实线程同步有好几种方法,下面我就...

weixin_33779515的博客 436

在Unity中为Sentis部署的YOLOv8模型集成NMS层并实现移动端性能优化

本文详细讲解了在Unity中利用Sentis部署YOLOv8模型时,如何通过代码动态集成NMS层以解决移动端性能瓶颈。文章核心在于避免导出时绑定NMS,转而使用Sentis原生API在运行时高效构建NMS处理流程,并分享了关键的GPU数据操作与移动端性能优化技巧,确保模型在移动设备上流畅运行。

p1q2r的博客 1094

同步和异步,进程,线程和协程之间的区别和联系

同步和异步、阻塞和非阻塞 异步: 多任务, 多个任务之间执行没有先后顺序,可以同时运行,执行的先后顺序不会有什么影响,存在的多条运行主线 同步: 多任务, 多个任务之间执行的时候要求有先后顺序,必须一个先执行完成之后,另一个才能继续执行, 只有一个主线 阻塞:从调用者的角度出发,如果在调用的时候,被卡住,不能再继续向下运行,需要等待,就说是阻塞 非阻塞: 从调用者的角度出发, 如果在调用的时候,...

当我把这件事情做出来的时候,我想要的东西就已经拿到了 5207

uniapp APP分享;判断用户是否安装APP,已安装直接打开,未安装跳转下载页;uniapp 在外部打开APP(schemes)

A将某商品分享给B,B点击后判断是否安装APP,若安装直接打开,没有安装则跳转下载页;

@微你 5681

手把手教你用键盘在Ubuntu上给Lerobot机械臂采集HIL-SERL训练数据(附完整配置文件)

本文详细介绍了在Ubuntu系统中使用键盘控制Lerobot机械臂进行HIL-SERL训练数据采集的完整流程。从环境准备、机械臂校准到键盘遥操系统配置和数据采集优化,提供了实战指南和常见问题解决方案,帮助读者高效获取高质量训练数据,推动具身智能和强化学习应用的发展。

weixin_30733003的博客 479

进程的并发执行(入门)

1、实现多线程 1.1 进程 进程:是正在运行的程序,是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源 1.2 线程 线程:是进程中的单个顺序控制流,是一条执行路径 单线程:一个进程如果只有一条执行路径,则称为单线程程序 多线程:一个进程如果有多条执行路径,则称为多线程程序 1.3 多线程的实现方式 方式1:继承Thread类 定义一个类MyThread...

dfy20505的博客 1976

小程序结合Three.js与gsap:打造流畅3D动画的完整指南

本文详细介绍了如何在小程序中整合Three.js与GSAP动画库,打造流畅的3D动画效果。通过从环境搭建、基础场景创建到模型加载与复杂动画编排的完整指南,帮助开发者克服小程序性能限制,实现如商品360度展示等沉浸式交互体验,提升产品视觉吸引力。

python9snake的博客 548

线程,进程,协程, 并发,并行,同步,异步概念解析

我相信线程,进程,协程, 并发,并行,同步,异步这几个概念大家在编程过程中肯定会遇到,但是偏偏这几个概念又那么类似,很容易让人模糊,今天我就用这一篇文章来和大家梳理一下这几个概念。

开源探索者 7145

一文读懂无人机AI识别算法,原理、技术、应用

本文详细介绍了无人机识别算法的工作原理、技术优势以及在多个行业的应用前景,展现了其在提升安全监控、资源管理和应急响应中的关键作用。尽管无人机识别算法在多个领域展现出巨大潜力,但仍面临技术挑战,如算法的准确性、数据的实时处理能力以及对复杂环境的适应性。4. 消防与城市管理: 无人机识别算法在消防和城市管理中的应用,为相关部门提供了及时的信息支持,提升了应急处置能力和城市管理水平。1. 公安监控: 无人机识别算法在公安领域的应用,可以实时识别犯罪嫌疑人和违法行为,有效提升城市治安管理的智能化水平。

foiadrone的博客 1849

Comsol实战:铌酸锂x切与z切参数设置全攻略(附电场强度归一化技巧)

本文详细介绍了在Comsol Multiphysics中设置铌酸锂x切与z切晶体参数的全流程,包括晶体取向定义、电光系数配置及关键光学参数计算。重点讲解了电场强度归一化这一实用技巧,帮助用户提升仿真分析效率,为设计电光调制器等集成光子器件提供精准的仿真基础。

year5的博客 583

线程、进程、协程与同步、异步、并行、并发的区别

特性进程线程协程定义操作系统分配资源的基本单位进程中的执行单元轻量级执行单元内存隔离独立内存空间共享进程内存共享线程内存通信进程间通信机制共享内存,通信方便共享内存,通信方便调度操作系统内核调度操作系统内核调度用户态程序控制调度开销高较低非常低特性同步异步并行并发定义任务按顺序执行,阻塞任务非阻塞,可以并行执行任务同时执行任务在同一时间段交替执行特点阻塞后续任务非阻塞,适合I/O密集型任务需要多核CPU,真正同时执行交替执行,表现为同时执行。

aksjebdjj的博客 932

传感器使用——ESP-WROOM-32 and INMP441麦克风音频采集

传感器使用——ESP-WROOM-32 and INMP441麦克风音频采集,数据显示及matlab操作界面。

qq_41958946的博客 7354

Python协程、线程、进程异步同步差异

同步: 多任务, 多个任务之间执行的时候要求有先后顺序,必须一个先执行完成之后,另一个才能继续执行, 只有一个主线 异步: 多任务, 多个任务之间执行没有先后顺序,可以同时运行,执行的先后顺序不会有什么影响,存在的多条运行主线 阻塞:从调用者的角度出发,如果在调用的时候,被卡住,不能再继续向下运行,需要等待,就说是阻塞 非阻塞: 从调用者的角度出发, 如果在调用的时候,没有被卡住,能够继续向下运行...

YPL_ZML的博客 426

YOLOv11改进 | 主干/Backbone篇 | 利用目标检测轻量化网络MobileNetV2替换Backbone(yolov11系列全系轻量化)

本文给大家带来的改进机制是,其是专为移动和嵌入式视觉应用设计的轻量化网络结构。其在MobilNetV1的基础上采用反转残差结构和线性瓶颈层。这种结构通过轻量级的深度卷积和线性卷积过滤特征,同时去除狭窄层中的非线性,以维持表征能力。MobileNetV2在性能上和精度上都要比V1版本强很多,其在多种应用(如对象检测、细粒度分类、面部属性识别和大规模地理定位)中都展现了一定的有效性。YOLOv11改进系列专栏——本专栏持续复习各种顶会内容——科研必备目录一、本文介绍二、MobileNetV2的框架原理。

Snu77的博客 2844

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

同步异步与协程线程进程关系

同步异步与协程线程进程关系. 参考:链接 主要看那个老张烧开水: 异步执行:老张(调用者),烧开水.是一个调用者-->烧开水.然后烧开水-->(反馈)调用者,调用者-->上水(剩余,直接先写)的过程. 有了协程,是不是可以不要异步了?应该就是!搞一堆协程池,都是干活的.这个事情完了,或者慢得很,就不管了,干其他事情,当反馈后,直接另外一个协程去干活. 应该就是这样.所谓的异步,不...

个人进步之路 762

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

关于进程、线程、协程、同步、异步、阻塞、非阻塞、并发、并行、串行的理解

二、线程 三、协程 七、非阻塞 八、并发 九、并行 十、串行

python全栈 1207

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

一文理解进程、线程、协程、高并发、同步、异步

进程是 “独立分店”:资源隔离,抗风险但成本高;线程是 “普通厨师”:共享资源,能并行干活,但数量多了效率下降;协程是 “超级厨师的任务清单”:极致轻量,用户自己调度,单线程能扛海量任务;同步 / 异步是 “干活方式”:同步是 “等完再干”(低效),异步是 “边等边干”(高效);高并发是 “客流高峰”:需要通过 “多进程分流 + 多线程并行 + 协程提效 + 异步减等待” 组合应对,最终实现 “客人满意,成本可控”。

qq_44065310的博客 800

Python 中的进程、线程、协程、同步、异步、回调

进程和线程究竟是什么东西?传统网络服务模型是如何工作的?协程和线程的关系和区别有哪些?IO过程在什么时间发生?在刚刚结束的 PyCon2014 上海站,来自七牛云存储的 Python 高级工程师许智翔带来了关于 Python 的分享《Python中的进程、线程、协程、同步、异步、回调》。在进一步之前,让我们先回顾一下各种上下文切换技术。不过首先说明一点术语。当我们说“上下文”的时候,指的是程序在执行中的一个状态。通常我们会用调用栈来表示这个状态——栈记载了每个调用层级执行到哪里,还有执行时的环境情况等所有有

m0_72444380的博客 941

python 基础 进程,线程,协程,并发并行,异步同步的定义

进程,线程,协程 进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 ​ 用大白话说就是系统执行某一项过程的行为,比如你用浏览器在线播放器播放一个神奇的小视频,而播放小视频这个行为就是一个进程。如果你决定缓存有点慢,又打开了一个新浏览器窗口,选择了另一个神奇的小视频,这就是两个进程。所以进程才说是一段程序的执行过程,而不是运行某个程序。所以记住运行一个程序会运行一个或者一个以上的进程。 线程:是操作系统能够进行运算调度的最小单位。它被包

u011863822的博客 299

线程、进程、协程、并发、并行、同步、异步

对于python代码,一个py文件可以理解为一个工厂(程序),其中可以有多个进程,一个进程下又可以有多个线程。对于多核心处理器:可以让不同的任务 同时的在多个核心上进行,是真正的并行,即下文中的Parallelism。为了提高产能,可以(1)创建多个车间,每个车间内1个工人各自使用其中车间的资源,也就是多进程;也可以(2)在一个车间中招进多个工人,所有工人公用车间内的资源,也就是多线程。也就是让不同的任务在同一条道路上执行,但是要分先后,上一个任务执行完才执行下一任务。多线程就是实现异步的一种方式。

LHB123456789L的博客 232

进程,协程,线程,同步,异步,阻塞,非阻塞,流量削锋(简单理解)

1.什么是进程,线程,协程 进程是一个"执行中的程序" 线程: 由于用户的并发请求,为每一个请求都创建一个进程显然是行不通的,从系统资源开销方面或者是响应用户请求的效率方面来看。因此操作系统中线程的概率便被引入了 线程,有时被称为轻量级进程,是程序执行流的最小单元 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行...

cangqiong_xiamen的博客 469

协程 进程_python协程之一:程序、进程、线程、协程、同步、异步概念

前面详细讲了python的线程,详细可以点击【python线程之十:线程 threading 最终总结】咱先了解一下一个程序大致是怎么组成的,再谈协程行不行。多进程程序:一个程序,最少需要一个进程,一个线程组成如果没有手工创建多进程、多线程,操作系统默认给创建,叫做主进程、主线程一个程序,为了提高效率一般会创建多进程、多线程、协程进程:进程是程序的实体多CPU可以同时执行多个进程,并行执行多线程:...

weixin_31876345的博客 84

切面是异步还是同步操作‘_线程,进程,协程, 并发,并行,同步,异步概念解析...

我相信线程,进程,协程, 并发,并行,同步,异步这几个概念大家在编程过程中肯定会遇到,但是偏偏这几个概念又那么类似,很容易让人模糊,今天我就用这一篇文章来和大家梳理一下这几个概念。1. 同步与异步当我们 同步 的执行某个任务时,我们需要等到这个任务执行完给我们反馈结果,我们才能去执行其他的任务。但是 异步 的执行某个任务时,我们可以不用等这个任务结束就去执行另一项任务。就像常用到的异步刷新操作。通...

weixin_39811842的博客 552

线程,进程,协程,异步和同步,非阻塞IO

1.线程,进程,协程 进程定义:进程是具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是系统进行资源分配和调度的一个独立单位 线程定义:线程是CPU调度和分派的基本单位,是比进程更小能独立运行的单位,线程占有系统。但是它可以与它同属的进程和其他在该进程中的线程共享这个进程中所用有的资源 关系: 一个进程最起码由一个线程组成(包括多个) 同一个进程中的多个线程可以并发执行 线程可以与同进程...

E.W的博客 1552
上一篇: 爬虫之滑动验证破解
下一篇: python常用模块
Are you ready
博客等级 码龄8年 312粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值