进程 线程 协程



多任务
单核执行多任务是假的多任务 是程序轮循进行
并⾏:指的是任务数⼩于等于cpu核数,即任务真的是⼀起执⾏的
并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法, 实现⽤多个任务“⼀起”执⾏(实际上总有⼀些任务不在执⾏,因为切换任 务的速度相当快,看上去⼀起执⾏⽽已) 


多线程:
import threding


def xxx():
    pass


t = threading.Thread(target=xxx)
t.start()


线程往往可以封装成类 继承于threading.Thread
重写run 方法


import threading
class MyThread(threading.Thread):
    def run(self):
for i in range(5)
    msg = "i am" + i


if __name__ == '__main__':
    t = MyThread()
    t.start()
多线程程序的执⾏顺序是不确定的 多线程之间共享全局变量


如果多线程同时对同一个全局变量操作 ,会出现资源竞争问题, 从而数据结果会不正确




import threading


total_num = 0




def count1(num):
    global total_num
    for i in range(num):
        total_num += 1
    print(total_num)




def count2(num):
    global total_num
    for i in range(num):
        total_num += 1
    print(total_num)


t1 = threading.Thread(target=count1, args=(1000000,))  # 传参使用元组
t1.start()
t2 = threading.Thread(target=count2, args=(1000000,))
t2.start()
# 1233158  1302644
如果要保证线程安全 可以使用互斥锁
import threading


total_num = 0




def count1(num):
    global total_num
    for i in range(num):
        metux.acquire()  # 上锁
        total_num += 1
        metux.release()  # 解锁
    print(total_num)




def count2(num):
    global total_num
    for i in range(num):
        metux.acquire()
        total_num += 1
        metux.release()
    print(total_num)
metux = threading.Lock()
t1 = threading.Thread(target=count1, args=(1000000,))  # 传参使用元组
t1.start()
t2 = threading.Thread(target=count2, args=(1000000,))
t2.start()  
#1946569   2000000


多进程
多进程之间不共享全局变量 
查看进程ip os.getpid()


from multiprocessing import Process
import time
def print1():
    for i in range(100):
        print("____{}____".format(i))
        time.sleep(0.01)


if __name__ == '__main__':
    p = Process(target=print1)
    p.start()
    for i in  range(100, 201):
        print("____{}____".format(i))
        time.sleep(0.01)


Process([group [,target[,name[,args[,kwargs]]]]])
target:如果传递了函数的引⽤,可以任务这个⼦进程就执⾏这⾥的代码 args:给target指定的函数传递的参数,以元组的⽅式传递
kwargs:给target指定的函数传递命名参数 
name:给进程设定⼀个名字,可以不设定 
group:指定进程组,⼤多数情况下⽤不到


start():启动⼦进程实例(创建⼦进程) 
is_alive():判断进程⼦进程是否还在活着 
join([timeout]):是否等待⼦进程执⾏结束,或等待多少秒 terminate():不管任务是否完成,⽴即终⽌⼦进程


进程于线程的区别
进程 一台电脑可以 运行多个QQ
线程 一个QQ 可以有多个窗口来聊天
进程是系统进行资源分配和调度的基本单位⼀个程序⾄少有⼀个进程,⼀个进程⾄少有⼀个线程.线线程不能够独⽴执⾏,必须依存在进程中线程和进程在使⽤上各有优缺点:线程执⾏开销⼩,但不利于资源的管理和 保护;⽽进程正相反


进程之间有时需要通信就要使用 queue
from multiprocessing import Queue 
q=Queue(3)  #初始化⼀个Queue对象,最多可接收三条put消息  
q.put("消息1")
q.put("消息2") 
print(q.full())  #False 
q.put("消息3") 
print(q.full()) #True


Queue.qsize():返回当前队列包含的消息数量;
Queue.empty():如果队列为空,返回True,反之False
Queue.full():如果队列满了,返回True,反之False;
Queue.get([block[,timeout]]):获取队列中的⼀条消息,然后将其从列队 中移除,block默认值为True;
如果block使⽤默认值,且没有设置timeout(单位秒),消息列队如果为 空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为⽌, 如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛 出"Queue.Empty"异常
进程池
需要手动生成的子进程多时,需要用的multiprocessing 的 Pool方法
from multiprocessing import Pool
import time, random, os




def worker(msg):


    t_strat = time.time()
    time.sleep(random.random()*2)
    print(msg, os.getpid())
    t_stop = time.time()


po = Pool(3)


for i in range(10):
    # apply_async(调用的目标,(参数元组))
    po.apply_async(worker, (i,))


po.close()  # 关闭进程池
po.join()  # 等待所有子进程执行完成


如果使用进程池进行进程之间的通信需要使用queue 但是不是multiprocessing中的Queue 而是 multiprocessing 中的Manage里面的Queue
from multiprocessing import Manager,Pool
import time


def reader(q):
    for i in range(q.qsize()):
        print(q.get())


def writer(q):
    for i in "work_hard":
        q.put(i)
q = Manager().Queue()
po = Pool(3)
po.apply_async(writer, (q,))
time.sleep(1)


po.apply_async(reader, (q,))


po.close()  # 关闭进程池
po.join()  # 等待子进程结束




可以遍历的对象 可迭代对象
判断方法 from colletions import Iterable
isinstance({}, Iterable) # True
迭代器 具备了__itea__ 方法和 __next__方法的对象就是一个迭代器
li = [11, 22, 33]
li_itea= itea(li)
next(li_itea) # 11
next(li_itea) # 22
next(li_itea) # 33
next(li_itea) # 报错 StopIteration
费伯纳尔数组
class FibIterator(object):
    def __init__(self, n):


        self.n = n
        self.current = 0
        self.num1 = 0
        self.num2 = 1


    def __next__(self):
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, (self.num1+self.num2)
            self.current += 1
            return num
        else:
            raise StopIteration


    def __iter__(self):
        return self


if __name__ == '__main__':
    fib = FibIterator(15)
    # for i in fib:
    #    print(i, end=" ** ")


    li = list(fib)
    print(li) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]


生成器 ⽣成器是⼀类特殊的迭代器
创建生成器
只需要把一个列表生成式的[] 换成()
A= (x*2 for x in range(5))
简单的生成器 简单来说 只要在函数中有yield 关键字的就叫做生成器
def fib(n):
    current = 0
    num1,num2 = 0,1
    while current < n:
num = num1
num1,num2 = num2, num1+num2
current +=1
yield num
    return "done"


我们除了可以使⽤next()函数来唤醒⽣成器继续执⾏外,还可以使⽤send()函 数来唤醒执⾏。使⽤send()函数的⼀个好处是可以在唤醒的同时向断点处传 ⼊⼀个附加数据


协程 又称为微线程


协程 通俗的理解:在⼀个线程中的某个函数,可以在任何地⽅保存当前函数的⼀ 些临时变量等信息,然后切换到另外⼀个函数中执⾏,注意不是通过调⽤函 数的⽅式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开 发者⾃⼰确定
grennlet 可以实现协程 但需要人工切换
gevent 加上 monkey 就可以更方便的使用协程
monkey.patch_all()  # 将程序的耗时操作交给程序自己处理




def work(worker_name):
    for i in range(10):
        print(worker_name, i)
        time.sleep(random.random())
# spawn 产卵 大量生产
gevent.joinall([
    gevent.spawn(work, "worker01"),
    gevent.spawn(work, "worker02"),
])


简单分析 进程 协程 线程
进程是系统资源分配的单位
线程是操作系统调度的单位
进程切换需要大量的资源 效率低
线程切换需要的资源一般 效率一般 
协程切换资源很小 ,效率高




 




























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值