进程-线程-异步

- 进程:就是程序-软件

- 一个进程就相当于一个任务,进程与进程之间互不干涉

- 当一个任务被开启后,操作系统会分配它所需的系统资源,包括内存,CPU等,如果系统资源不够,则会出现系统崩溃,这样的任务可以被称为进程

- 进程需要口粮:CPU和内存,当资源不足时,系统可能会奔溃

- 多进程是一种并行的模式,不同于单进程(串行),多进程的效率更高

- 多进程在不同的内核跑道中执行叫做多进程的并行处理

- 线程是执行程序的最小单元

- 进程提供线程执行程序的前置要求,线程在充足的资源配置下,执行程序

- 线程是操作系统最小执行单元,一个进程至少由一个线程组成

- 进程被运行后算一个线程,进程是不运行的,线程才会运行,而一个进程有多个线程就涉及到进程有多少可以被cpu单独调用的模块,这个调用的模块可以通过手动创建线程来建立

- 进程是吸收资源的,而线程是干活的。

- 进程间不可以共享内存,而线程却可以

- 线程可手动创建或者撤销另一个线程

- 进程需要引用第三方模块multiprocessing ,调用方式为multiprocessing.process(target='')

- 线程需要引用第三方模块threading,调用方式为threading.Thread(trager='',name='')

- 一个核心中在多个时间片上同时处理线程的行为叫做并发执行

- 多个CPU之间同时执行叫并行;单个CPU内核中多个线程同时工作叫并发;不过一般工作中都会叫并发统称,名词上的统称,不用纠结

import time,os
import multiprocessing

def work_a():
    for i in range(3):
        print(i,'a',os.getpid())
        # print('对应进程ID',os.getpid())
        time.sleep(1)

def work_b():
    for i in range(3):
        print(i,'b',os.getpid())
        time.sleep(1)

def work_c():
    for i in range(3):
        print(i,'c',os.getpid())
        time.sleep(1)

if __name__=="__main__":
    start = time.time() # 主进程
    c_p = multiprocessing.Process(target=work_c)# 子进程c
    c_p.start()# 子进程c执行
    c_p.join()
    a_p = multiprocessing.Process(target=work_a)# 子进程a
    a_p.start() # 子进程a执行
    # work_a()
    # work_b()

    # # 可以使用for循环减少代码
    # for p in (c_p,a_p):
    #     p.start()
    #
    # # 使用join阻塞,可以让主进程等子进程全部执行完之后再执行
    # for p in (c_p,a_p):
    #     p.join()

    for p in (c_p,a_p):
        print(p.is_alive())

    print('主进程时间消耗',time.time()-start) # 主进程
    print('主进程ID',os.getpid())

- 进程池与进程锁

- 一、创建进程锁

在进程代码中需要加上锁的地方写加锁代码,要释放锁的地方写解锁代码既可:

使用模块:multiprocessing

如何加锁:multiprocessing.Manager().Lock().acquire()

如何解锁:multiprocessing.Manager().Lock().release()

创建进程池:先写出创建进程池的方法,之后往进程池中放入进程即可

使用的模块:multiprocessing

创建的方法:multiprocessing.Pool(...)

二、使用进程池的优势a

不仅能制定进程创建的数量,还可以避免进程的创建于关闭带来的消耗

pool = multiprocessing.Pool(4)

manager = multiprocessing.Manager()

lock = manager.Lock()

lock.acquire()

import time,os
import multiprocessing

def work_a():
    for i in range(3):
        print(i,'a',os.getpid())
        # print('对应进程ID',os.getpid())
        time.sleep(1)

def work_b():
    for i in range(3):
        print(i,'b',os.getpid())
        time.sleep(1)

def work_c():
    for i in range(3):
        print(i,'c',os.getpid())
        time.sleep(1)

if __name__=="__main__":
    start = time.time() # 主进程
    c_p = multiprocessing.Process(target=work_c)# 子进程c
    c_p.start()# 子进程c执行
    c_p.join()
    a_p = multiprocessing.Process(target=work_a)# 子进程a
    a_p.start() # 子进程a执行
    # work_a()
    # work_b()

    # # 可以使用for循环减少代码
    # for p in (c_p,a_p):
    #     p.start()
    #
    # # 使用join阻塞,可以让主进程等子进程全部执行完之后再执行
    # for p in (c_p,a_p):
    #     p.join()

    for p in (c_p,a_p):
        print(p.is_alive())

    print('主进程时间消耗',time.time()-start) # 主进程
    print('主进程ID',os.getpid())
    # var1 = multiprocessing.Process()

import multiprocessing
import os
import time


def work(count):
    print(str(count)+'a',os.getpid())
    time.sleep(1)

def work_b(count):
    print(str(count) + 'b', os.getpid())
    time.sleep(1)
    return 'work_b返回值 %s pid:%s'% (count,os.getpid())

def work_c(count,lock):
    lock.acquire()
    print(str(count) + 'b', os.getpid())
    time.sleep(1)
    lock.release()
    return 'work_b返回值 %s pid:%s'% (count,os.getpid())


if __name__=='__main__':
    pool = multiprocessing.Pool(4)
    manager = multiprocessing.Manager()
    lock = manager.Lock()
    # for i in range(20):
    #     pool.apply_async(func=work,args=(i,)) # args是个元组,单个参数时记得加,
    # pool.close() #实际生产中,有的进程需要一直运行着,就不用关闭
    # pool.join() # 和close一起用

    # results = []
    # for i in range(20):
    #     # apply_async 异步可以有返回值
    #     pool_re = pool.apply_async(func=work_b,args=(i,))
    #     results.append(pool_re)
    #
    # for res in results:
    #     print(res.get())

    # print(len(results),results)
    for i in range(20):
        pool.apply_async(func=work_c,args=(i,lock))
        # print('====')

    # time.sleep(20)
    pool.close() #实际生产中,有的进程需要一直运行着,就不用关闭
    pool.join() # 和close一起用

进程之间的通信:

import json
import multiprocessing
import time
# 有问题,没解决,采用直接函数调用试试

class Work(object):
    def __init__(self,q):
        self.q = q
        # print(self.q, type(self.q))

    def send(self,message):
        print(self.q,type(self.q))
        try:
            # 如果不是字符串格式的,要json序列化为字符串格式在传输
            # json.dumps(obj)对象序列化为字符串
            # 序列化:对象信息 / 数据结构信息,转化为字符串
            if not isinstance(message,str):
                message = json.dumps(message)
        except Exception as e:
            print(e)
        self.q.put(message)

    def receive(self):
        while 1:
            result = self.q.get()
            try:
                res = json.loads(result)
            except:
                res = result
            print('receive massage is %s'% res)

    def all_send(self):
        for i in range(10):
            self.q.put(i)
            time.sleep(1)


if __name__ == '__main__':
    q = multiprocessing.Queue()
    work = Work(q)
    send = multiprocessing.Process(target=work.send,args=({'name':'xiaoming'},))
    recv = multiprocessing.Process(target=work.receive)
    all_send_p = multiprocessing.Process(target=work.all_send)

    all_send_p.start()
    send.start()
    recv.start()

    all_send_p.join() # 只需要阻塞最长使用时间的进程
    recv.terminate() #正常退出接收方

队列02:

import json
import multiprocessing
import queue
import random
import threading
import time
# 线程

def sender():
    # print(q,type(q))
    while 1:
        x = random.randint(1,10)
        print('send num:',x)
        q.put(x) # 往队列中放入数据
        time.sleep(1)
        # if x+5>14:
        #     return

def recvder():
    while 1:
        result = q.get() # 从队列中取数据
        # try:
        #     res = json.loads(result)
        # except:
        #     res = result
        print('receive num:%s'% result*3)
        time.sleep(1)
        # if result == 10:
        #     break

# def all_send(q):
#     for i in range(10):
#         q.put(i)
#         time.sleep()


if __name__ == '__main__':
    q = queue.Queue() # 定义队列
    send = threading.Thread(target=sender)
    recv = threading.Thread(target=recvder)
    # all_send_p = multiprocessing.Process(target=all_send)

    # all_send_p.start()
    send.start()
    recv.start()

    # send.join()
    # recv.join()
    # all_send_p.join() # 只需要阻塞最长使用时间的进程

- 多线程运行时,可能出现的问题及解决方案:

1、通过线程执行的函数无法获取返回值——【解决方案】线程间如何通信:通过队列

2、 多个线程同时修改文件可能造成数据错乱。——解决方案】线程间如何避免资源抢占:创建线程锁

3、线程数量太多可能会造成资源不足,甚至死机等情况。——【解决方案】如何避免创建线程数量过多:线程池

- 通过队列通信解决

- 创建线程锁

- 使用模块:threading

- 如何加锁:threading.Lock().acquire()

- 如何解锁:threading.Lock().release()

- 创建线程池

- 使用模块:concurrent.futures

- 创建方法:concurrent.futures.ThreadPoolExcutor()

import random
import threading
import time

books = ['python','flask','C++','java','flutter',
         'golang','spring boot']

new_list = []

def work():
    if len(books) == 0:
        return
    else:
        data = random.choice(books)
        _data = '%s_new'% data
        new_list.append(_data)
        books.remove(data)
    time.sleep(1)

if __name__=='__main__':
    start_time = time.time()
    # for i in range(len(books)-3):
    #     work()
    t_list = []
    # 使用多线程缩短运行时间
    for i in range(len(books)-3):
        t = threading.Thread(target=work)
        t_list.append(t)
        t.start()
    # for t in t_list:
    #     t.join()

    print('old list:',books)
    print('new list:',new_list)
    print('时间花费为 %s'%(time.time()-start_time))


线程池
import os
import time
from concurrent.futures import ThreadPoolExecutor
import threading

# 使用线程锁时,只用在全局定义线程锁即可,不需要传入函数中,作为参数加锁
# 进程,需要放入函数中,进行加锁
lock = threading.Lock() # 这个才是<class '_thread.lock'>
lock1 = threading.Lock
# <built-in function allocate_lock> <class 'builtin_function_or_method'>

def work_a(i):
    lock.acquire()
    print(i,'a',os.getpid())
    time.sleep(1)
    lock.release()

def work_b(i):
    print(i,'b',os.getpid())
    time.sleep(1)
    return 'result is %s a'% i

if __name__=='__main__':
    print(lock,type(lock))
    print(lock1,type(lock1))
    tpool = ThreadPoolExecutor(2)
    # for i in range(10):
    #     tpool.submit(work_a,(i,))
    # print('=======')

    # 线程值 获取返回值work_b
    result = []
    for i in range(10):
        t_result = tpool.submit(work_b,(i,))
        result.append(t_result)

    time.sleep(10)
    for res in result:
        print(res,res.result(),'res') # res.result()获取当前线程执行任务的结果
    print('----',os.getpid())

- 进程锁与线程锁的区别

- 使用线程锁时,只用在全局定义线程锁即可,不需要传入函数中,作为参数加锁

- 进程,需要放入函数中,进行加锁

- 全局锁GIL(python解释器自带的) 使得python的多线程只能在单一cpu上工作,目的是为了保证线程的安全

- 解决方式:pypy解释器(不太推荐),多进程+多线程:通过多个进程在每个CPU跑道上,每个跑道上再执行多线程,去到各自的cpu时间片上执行

- 什么是全局锁

python有全局锁gil,多线程只能在单一cpu工作。可以用多进程+多线程配合使用

python无法在多条跑道执行任务的主要原因就是因为GIL全局锁(初步理解没有去掉GIL锁的原因是:线程安全)

全局锁的主要作用

因为多线程的编程方式,使得线程之间的数据的一致性和状态同步难以把控,为了解决数据不能同步的问题,设计了GIL全局解释器锁。

全局锁是如何发挥作用的

在Cpython解锁器中,当python代码有一个线程开始访问解释器的时候,GIL会把这个线程给锁上,此时此刻其他的线程只能干等着,无法对解释器的资源进行访问,需要等这个线程分配的时间到了,这个线程把GIL释放掉,另外的线程才开始跑起来,其实这无疑也是一个单线程。这类似于给线程加锁threading.Lock(),解锁threading.Lock().release()一样。

# 异步 async,await,asyncio,gevent

- 异步:轻量级的线程—协程;可以获取异步函数返回值

- 多进程和多线程,可以随时创建使用(虽然多进程每一次创建都会消耗一些CPU资源),但是异步有要求,主进程必须是异步的情况下才可以使用,并且执行过程中所有的程序都是异步才行

- 因为异步有返回值,所以更适合类似于文件读写(需要返回值的业务),而多进程和多线程更适合业务处理,不需要返回值的工作

- 多进程,多线程,异步,都是通过函数来处理,异步函数使用async 定义,await执行异步

- gevent python2就出现了,不同环境用不同的,

- 查看错误信息,然后解决

- 异步总结

- 相对于同步而言,异步意味着无序。正因为异步的无序,使得各个程序间的协调成为一大难题

- 异步编程就是为了解决这一问题的编程方式,它以进程、线程、协程、函数/方法作为执行任务程序的基本单位,结合回调、事件循环、信号量等机制,以提高程序整体执行效率和并发能力的编程方式

- 关于异步 记住三对

- 关键词: async 定义声明 ,await main()中调用执行

- 模块:asyncio(调用异步函数) 加入asyncio.gather() 执行asyncio.run()

- 第三方模块:gevent异步包

- 创建协程对象gevent.spwan() 批量处理协程对象 gevent.joinall()

import os
import random
import time
import asyncio
import gevent


def gevent_a():
    for i in range(5):
        print(i,'a-gevent',os.getpid())
        gevent.sleep(random.random()*2)
    return 'gevent a result'

def gevent_b():
    for i in range(5):
        print(i,'b-gevent',os.getpid())
        gevent.sleep(random.random()*2)
    return 'gevent b result'

def work_a():
    for i in range(10):
        print(i,'a')
        time.sleep(random.random()*2)
    return 'a-func'

def work_b():
    for i in range(10):
        print(i,'b')
        time.sleep(random.random()*2)
    return 'b-func'

async def work_c():
    for i in range(10):
        print(i,'c',os.getpid())
        await asyncio.sleep(random.random()*2)
    return 'c-func'

async def work_d():
    for i in range(10):
        print(i,'d',os.getpid())
        await asyncio.sleep(random.random()*2)
    return 'd-func'
# time.sleep()是CPU级别的阻塞,他会阻塞异步效果
# 解决方法,time.sleep()更换为asyncio.sleep()
# asyncio.sleep()和 gevent.sleep()业务级别的阻塞


# 调用异步函数,需要定义异步函数主函数
# 用asyncio.gather()调用批量执行,await声明执行
async def main():
    result = await asyncio.gather(
        work_d(),
        work_c()
    )
    print(result)
    print(result[0],result[1])

if __name__== '__main__':
    start = time.time()
    # work_a()
    # work_b()
    # asyncio.run(main())#执行主异步函数

    g_a = gevent.spawn(gevent_a) # 创建协程对象
    g_b = gevent.spawn(gevent_b)
    print(g_a,type(g_a))
    gevent_list = [g_a,g_b]
    # 也可以用g_b.run()或者g_b.start()启动
    result = gevent.joinall(gevent_list)#批量处理协程对象
    print('===',result)
    print(dir(result[0]))
    print(result[0].value)
    print(result[1].value)

    print(time.time()-start)
    print('主进程',os.getpid())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值