Python 高级教程之线程进程和协程

p.start()

第二种方法:

#方法二:manage.dict()共享数据

from multiprocessing import Process,Manager #这个特殊的数据类型Manager

manage = Manager()

dic = manage.dict() #这里调用的时候,使用字典,这个字典和咱们python使用方法是一样的!

def Foo(i):

dic[i] = 100+i

print dic.values()

for i in range(2):

p = Process(target=Foo,args=(i,))

p.start()

p.join()

既然进程之间可以进行共享数据,如果多个进程同时修改这个数据是不是就会造成脏数据?是不是就得需要锁!

进程的锁和线程的锁使用方式是非常一样的知识他们是用的类是在不同地方的。

进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

  • apply

  • apply_async

#!/usr/bin/env python

-- coding:utf-8 --

from multiprocessing import Process,Pool

import time

def Foo(i):

time.sleep(2)

return i+100

def Bar(arg):

print arg

pool = Pool(5) #创建一个进程池

#print pool.apply(Foo,(1,))#去进程池里去申请一个进程去执行Foo方法

#print pool.apply_async(func =Foo, args=(1,)).get()

for i in range(10):

pool.apply_async(func=Foo, args=(i,),callback=Bar)

print ‘end’

pool.close()

pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

‘’’

apply 主动的去执行

pool.apply_async(func=Foo, args=(i,),callback=Bar) 相当于异步,当申请一个线程之后,执行FOO方法就不管了,执行完之后就在执行callback ,当你执行完之后,在执行一个方法告诉我执行完了

callback 有个函数,这个函数就是操作的Foo函数的返回值!

‘’’

进程的缺点

无法即时完成的任务带来大量的上下文切换代价与时间代价。

进程的上下文:当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。

上下文切换:当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够得到切换时的状态并执行下去。

线程


线程的定义

在计算中,进程是正在执行的计算机程序的一个实例。任何进程都有 3 个基本组成部分:

  • 一个可执行程序。

  • 程序所需的相关数据(变量、工作空间、缓冲区等)

  • 程序的执行上下文(进程状态)

线程是进程中可以调度执行的实体。此外,它是可以在 OS(操作系统)中执行的最小处理单元。

简而言之,线程是程序中的一系列此类指令,可以独立于其他代码执行。为简单起见,您可以假设线程只是进程的子集!

线程在线程控制块 (TCB)中包含所有这些信息:

  • 线程标识符:为每个新线程分配唯一 id (TID)

  • 堆栈指针:指向进程中线程的堆栈。堆栈包含线程范围内的局部变量。

  • 程序计数器:存放线程当前正在执行的指令地址的寄存器。

  • 线程状态:可以是running、ready、waiting、start或done。

  • 线程的寄存器集:分配给线程进行计算的寄存器。

  • 父进程指针:指向线程所在进程的进程控制块 (PCB) 的指针。

多线程被定义为处理器同时执行多个线程的能力。

在一个简单的单核 CPU 中,它是通过线程之间的频繁切换来实现的。这称为上下文切换。在上下文切换中,只要发生任何中断(由于 I/O

或手动设置),就会保存一个线程的状态并加载另一个线程的状态。上下文切换发生得如此频繁,以至于所有线程似乎都在并行运行(这被称为多任务)。

在 Python 中,threading模块提供了一个非常简单直观的 API,用于在程序中生成多个线程。

使用线程模块的简单示例

让我们考虑一个使用线程模块的简单示例:

Python程序说明线程的概念

导入线程模块

import threading

def print_cube(num):

“”"

打印给定数字立方的函数

“”"

print(“立方: {}”.format(num * num * num))

def print_square(num):

“”"

打印给定数字平方的函数

“”"

print(“平方: {}”.format(num * num))

if name == “main”:

creating thread

t1 = threading.Thread(target=print_square, args=(10,))

t2 = threading.Thread(target=print_cube, args=(10,))

starting thread 1

t1.start()

starting thread 2

t2.start()

等到线程 1 完全执行

t1.join()

等到线程 2 完全执行

t2.join()

两个线程完全执行

print(“完成!”)

平方: 100

立方: 1000

完成!

代码解析

让我们试着理解上面的代码:

  • 要导入线程模块,我们这样做:

import threading

  • 要创建一个新线程,我们创建一个Thread类的对象。它需要以下参数:

  • target : 线程要执行的函数

  • args:要传递给目标函数的参数

在上面的示例中,我们创建了 2 个具有不同目标函数的线程:

t1 = threading.Thread(target=print_square, args=(10,))

t2 = threading.Thread(target=print_cube, args=(10,))

  • 要启动一个线程,我们使用 Thread 类的 start 方法。

t1.start()

t2.start()

  • 一旦线程启动,当前程序(你可以把它想象成一个主线程)也会继续执行。为了在线程完成之前停止当前程序的执行,我们使用join方法。

t1.join()

t2.join()

结果,当前程序将首先等待 t1 的完成,然后 t2 。一旦它们完成,则执行当前程序的剩余语句。

协程


协程(Coroutine,又称微线程,纤程)是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制。

我们都熟悉函数,也称为子例程、过程、子过程等。函数是打包为一个单元以执行特定任务的指令序列。当一个复杂函数的逻辑被分成几个独立的步骤,这些步骤本身就是函数时,这些函数被称为辅助函数或子程序。

Python 中的子程序由负责协调这些子程序的使用的主函数调用。子程序只有一个入口点。 协程是子程序的泛化。它们用于协作式多任务处理,其中一个进程定期或在空闲时自愿放弃(放弃)控制权,以使多个应用程序能够同时运行。协程和子程序的区别是:

  • 与子程序不同,协程有许多用于暂停和恢复执行的入口点。协程可以暂停其执行并将控制权转移给其他协程,并且可以从中断点重新开始执行。

  • 与子程序不同,没有主函数可以按特定顺序调用协程并协调结果。协程是协作的,这意味着它们链接在一起形成管道。一个协程可能会使用输入数据并将其发送给其他处理它的协程。最后,可能会有一个协程来显示结果。

协程与线程

现在您可能在想协程与线程有何不同,两者似乎都在做同样的工作。

在线程的情况下,它是根据调度程序在线程之间切换的操作系统(或运行时环境)。而在协程的情况下,决定何时切换协程的是程序员和编程语言。协程通过程序员在设定点暂停和恢复来协同工作多任务。

Python 协程

在 Python 中,协程类似于生成器,但几乎没有额外的方法,而且我们使用yield语句的方式也有细微的变化。生成器为迭代生成数据,而协程也可以使用数据

在 Python 2.5 中,引入了对 yield 语句的轻微修改,现在 yield 也可以用作表达式。例如在作业的右侧——

line = (yield)

我们发送给协程的任何值都会被(yield)表达式捕获并返回。

可以通过send()方法将值发送到协程。例如,考虑这个协程,它打印出带有前缀“Dear”的名称。我们将使用 send() 方法将名称发送到协程。

用于演示协程执行的 Python3 程序

def print_name(prefix):

print(“Searching prefix:{}”.format(prefix))

while True:

name = (yield)

if prefix in name:

print(name)

调用协程,什么都不会发生

corou = print_name(“Dear”)

这将开始执行协程并打印第一行 “Searching prefix…”

并将执行推进到第一个 yield 表达式

corou.next()

发送输入

corou.send(“Haiyong”)

corou.send(“Dear Haiyong”)

输出:

Searching prefix:Dear

Dear Haiyong

协程的执行

协程的执行类似于生成器。当我们调用协程时,什么都没有发生,它只在响应next()send ()方法时运行。在上面的例子中可以清楚地看到这一点,因为只有在调用__next__()方法之后,我们的协程才开始执行。在这个调用之后,执行前进到第一个 yield 表达式,现在执行暂停并等待值被发送到 corou 对象。当第一个值被发送给它时,它会检查前缀和打印名称(如果存在前缀)。打印完名称后,它会遍历循环,直到再次遇到name = (yield)表达式。

关闭协程

协程可能无限期运行,关闭协程使用close()方法。当协程关闭时,它会生成GeneratorExit异常,该异常可以以通常捕获的方式捕获。关闭协程后,如果我们尝试发送值,它将引发StopIteration异常。下面是一个简单的例子:

Python3 program for demonstrating

closing a coroutine

def print_name(prefix):

print(“Searching prefix:{}”.format(prefix))

try :

while True:

name = (yield)

if prefix in name:

print(name)

except GeneratorExit:

print(“关闭协程!!”)

corou = print_name(“Dear”)

corou.next()

corou.send(“Haiyong”)

corou.send(“Dear Haiyong”)

corou.close()

输出:

搜索前缀:Dear

Dear Haiyong

关闭协程!!

如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费学习大礼包,带大家一起学习,给大家剖析Python兼职、就业行情前景的这些事儿。

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

五、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值