(并发编程)进程池线程池--提交任务的2种方式、协程--yield greenlet,gevent模块

一:进程池与线程池(同步,异步+回调函数)
先造个池子,然后放任务
为什么要用“池”:池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务
池子内什么时候装进程:并发的任务属于计算密集型
池子内什么时候装线程:并发的任务属于IO密集型

#提交任务的两种方式:
    # 同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行的
    # 异步调用:提交完一个任务之后,不在原地等待,结果???,而是直接执行下一行代码,会导致任务是并发执行的
 
p=ProcessPoolExecutor(4) 
obj=p.submit(函数名,参1,参2)
obj.add_done_callback(函数名2)

#后续回调是obj会将自身传给函数名2,所以函数名2必须有且仅有一个参数。(多进程,回调主进程干)(多线程回调,子线程们干除开主线程)
p.shutdown(wait=True)#(等同于p.close()(不允许向池中放新任务) + p.join())关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕
obj.result()

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,random,os

def task(name,n):
    print(‘%s%s is running‘ %(name,os.getpid()))
    time.sleep(random.randint(1,3))
    return n**2

if __name__ == ‘__main__‘:
    # print(os.cpu_count())
    p=ProcessPoolExecutor(4)
    #提交任务的两种方式:
    # 同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行的
    # 异步调用:提交完一个任务之后,不在原地等待,结果???,而是直接执行下一行代码,会导致任务是并发执行的

l=[]
    for i in range(10):
        # 同步提交
        # res=p.submit(task,‘进程pid: ‘,i).result()
        # print(res)

# 异步提交
        future=p.submit(task,‘进程pid: ‘,i)
        l.append(future)

p.shutdown(wait=True) #关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕

for future in l:
        print(future.result())
    print(‘主‘)

‘‘‘
二、协程
1、协程是单线程实现并发
    注意:协程是程序员意淫出来的东西,操作系统里只有进程和线程的概念(操作系统调度的是线程)

在单线程下(i/o密集型任务)实现多个任务间遇到IO就切换就可以降低单线程的IO时间,从而最大限度地提升单线程的效率
  在单线程下(计算密集型任务)切反而降低效率。
2、实现并发的三种手段:
a单线程下的并发;由程序自己控制,相对速度快
b多线程下的并发;由操作系统控制,相对速度较慢
c多进程下的并发;由操作系统控制,相对速度慢

3、基于yield保存状态,实现两个任务直接来回切换,即并发的效果 (但yield不会遇到阻塞自动切程序)
   PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.

import time
def consumer():
    ‘‘‘任务1:接收数据,处理数据‘‘‘
    while True:
        x=yield

def producer():
    ‘‘‘任务2:生产数据‘‘‘
    g=consumer()
    next(g)
    for i in range(10000000):
        g.send(i)

start=time.time()
producer() #1.0202116966247559
stop=time.time()
print(stop-start)

# 纯计算的任务并发执行
import time
def task1():
    res=1
    for i in range(1000000):
        res+=i
        yield
        time.sleep(10000)  #yield不会自动跳过阻塞
        print(‘task1‘)

def task2():
    g=task1()
    res=1
    for i in range(1000000):
        res*=i
        next(g)
        print(‘task2‘)

start=time.time()
task2()
stop=time.time()
print(stop-start)

4、单线程下实现遇到IO切换
 1、用greenlet(封装yield,遇到IO不自动切)
 from greenlet import greenlet
 import time

def eat(name):
  print(‘%s eat 1‘ %name)
  time.sleep(30)
  g2.switch(‘alex‘)  #只在第一次切换时传值
  print(‘%s eat 2‘ %name)
  g2.switch()
 def play(name):
  print(‘%s play 1‘ %name)
  g1.switch()
  print(‘%s play 2‘ %name)

g1=greenlet(eat)
 g2=greenlet(play)
 g1.switch(‘egon‘)

2、用gevent模块(封装greenlet,不处理的话,遇到自己的IO才主动切)
 import gevent

def eat(name):
  print(‘%s eat 1‘ %name)
  gevent.sleep(5)  #换成time.sleep(5),不会自动切
  print(‘%s eat 2‘ %name)
 def play(name):
  print(‘%s play 1‘ %name)
  gevent.sleep(3)
  print(‘%s play 2‘ %name)

g1=gevent.spawn(eat,‘egon‘)
 g2=gevent.spawn(play,‘alex‘)

# gevent.sleep(100)
 # g1.join()
 # g2.join()
 gevent.joinall([g1,g2])

5、用gevent模块(封装greenlet,处理的话,遇到其他IO也主动切)
from gevent import monkey;monkey.patch_all()
from threading import current_thread
from gevent import spawn,joinall #pip3 install gevent
import time

def play(name):
    print(‘%s play 1‘ %name)
    time.sleep(5)
    print(‘%s play 2‘ %name)

def eat(name):
    print(‘%s eat 1‘ %name)
    time.sleep(3)
    print(‘%s eat 2‘ %name)

g1=spawn(play,‘刘清正‘)
g2=spawn(eat,‘刘清正‘)

# g1.join()
# g2.join()
joinall([g1,g2])

原文地址:https://www.cnblogs.com/3sss-ss-s/p/9621591.html

时间: 2024-10-11 21:49:40

(并发编程)进程池线程池--提交任务的2种方式、协程--yield greenlet,gevent模块的相关文章

Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析

目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolExecutor创建线程池实例 参考: 引出线程池 线程是并发编程的基础,前面的文章里,我们的实例基本都是基于线程开发作为实例,并且都是使用的时候就创建一个线程.这种方式比较简单,但是存在一个问题,那就是线程的数量问题. 假设有一个系统比较复杂,需要的线程数很多,如果都是采用这种方式来创建线程的话,那么

JAVA - 并发编程 - 执行器和线程池

思考? 1 为什么要使用执行器和线程池? 2 执行器和线程是什么?怎么使用 执行器 线程执行器分离了任务的创建和执行,提高了线程的性能 线程池 避免了频繁地创建和销毁线程,达到线程对象的重用,可以根据项目灵活地控制并发的数量 ExecutorService (java.util.concurrent) 1 Executors.newCachedThreadPool() 可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程 2 Executors.newFixedT

并发编程 — 详解线程池

本文将讲述如何通过JDK提供的API自定义定制的线程池 Java代码   //固定线程数 -- FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } //单

并发编程—7.2线程池基础

目录 1.什么是线程池?为什么要用线程池? 2.实现一个我们自己的线程池 3.JDK中的线程池和工作机制 3.1 线程池的创建 3.2 提交任务 3.3 关闭线程池 3.4 工作机制 4.合理配置线程池 5.预定义的线程池 6.Executor框架 7.了解CompletionService 1.什么是线程池?为什么要用线程池? 降低资源的消耗.线程的创建和销毁 提高响应速度.线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间 提高线程的可管理性. 2.实现一个我们自己的线程

并发编程 --- 进程,线程

目录 进程 线程 进程 1.进程互斥锁 异步可以让多个任务在几个进程中并发处理,他们之间没有运行顺序,一旦开启也不受我们的控制,尽管并发编程让我们更加充分的利用IO资源,但是当多个进程使用同一份资源的时候,就会引发数据安全或顺序混乱的问题 import json import time from multiprocessing import Process from multiprocessing import Lock # 查看余票 def search(user): # 打开data文件查看

Java并发编程--进程与线程

进程:百度百科说"进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.",维基百科说"是计算机中已运行程序的实体.进程本身不会运行,是线程的容器." 线程:百度百科说"线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元",维基百科说"是操作系统能够进行运算调度的最小单位.它被包涵在进程之中,是进程中的实际运作单位

CSIC_716_20191207【并发编程---进程与线程】

僵尸进程与孤儿进程 守护进程, from Multiprocessing  import Process 在 suboprocess.start( ) 的上一行,增加 subprocess.deamon( ),创建守护进程.当主进程执行完成时,subprocess也会被强制结束. 进程之间是相互独立的,主子两个进程在执行时,数据是隔离的. 进程互斥锁: from Multiprocessing import Lock lock = Lock( ) lock.acquire( ) #加锁 lock

Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池

目录 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 2.死锁现象与递归锁 2.1死锁现象 2.2递归锁 3.信号量 4.GIL全局解释器锁 4.1背景 4.2为什么加锁 5.GIL与Lock锁的区别 6.验证计算密集型IO密集型的效率 6.1 IO密集型 6.2 计算密集型 7.多线程实现socket通信 7.1服务端 7.2客户端 8.进程池,线程池 Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池 1.昨日回顾 #生产者消

并发编程---线程queue---进程池线程池---异部调用(回调机制)

线程 队列:先进先出 堆栈:后进先出 优先级:数字越小优先级越大,越先输出 import queue q = queue.Queue(3) # 先进先出-->队列 q.put('first') q.put(2) # q.put('third') # q.put(4) #由于没有人取走,就会卡主 q.put(4,block=False) #等同于q.get_nowait(), Ture 阻塞,Flase不阻塞,报异常满了 # # q.put(4,block=True,timeout=3) prin