程序间通讯方式

程序间通讯方式,第1张

程序间通讯方式

用于程序间通讯(IPC)的四种不同技术: 1. 讯息传递(管道,FIFO,posix和system v讯息伫列) 2. 同步(互斥锁,条件变数,读写锁,档案和记录锁,Posix和System V讯号灯) 3. 共享记忆体区(匿名共享记忆体区,有名Posix共享记忆体区,有名System V共享记忆体区) 4. 过程呼叫(Solaris门,Sun RPC) 讯息伫列和过程呼叫往往单独使用,也就是说它们通常提供了自己的同步机制.相反,共享记忆体区通常需要由应用程式提供的某种同步形式才能正常工作.解决某个特定问题应使用哪种IPC不存在简单的判定,应该逐渐熟悉各种IPC形式提供的机制,然后根据特定应用的要求比较它们的特性. 必须考虑的四个前提: 1. 联网的还是非联网的.IPC适用于单台主机上的程序或执行绪间的.如果应用程式有可能分布到多台主机上,那就要考虑使用套接字代替IPC,从而简化以后向联网的应用程式转移的工作. 2. 可移植性. 3. 效能,在具体的开发环境下执行测试程式,比较几种IPC的效能差异. 4. 实时排程.如果需要这一特性,而且所用的系统也支援posix实时排程选项,那就考虑使用Posix的讯息传递和同步函式. 各种IPC之间的一些主要差异: 1. 管道和FIFO是位元组流,没有讯息边界.Posix讯息和System V讯息则有从传送者向接受者维护的记录边界(eg:TCP是没有记录边界的位元组流,UDP则提供具有记录边界的讯息). 2. 当有一个讯息放置到一个空伫列中时,Posix讯息伫列可向一个程序传送一个讯号,或者启动一个新的执行绪.System V则不提供类似的通知形式. 3. 管道和FIFO的资料位元组是先进先出的.Posix讯息和System V讯息具有由传送者赋予的优先顺序.从一个Posix讯息伫列读出时,首先返回的总是优先顺序最高的讯息.从一个System V讯息伫列读出时,读出者可以要求想没核要的任意优先顺序的讯息. 4. 在众多的讯息传递技术—管道,FIFO,Posix讯息伫列和System V讯息伫列—中,可从一个讯号处理程式中呼叫的函式只有read和write(适用于管道和FIFO). 比较不同形式的讯息传递时,我们感兴趣的有两种测量尺度: 1. 频宽(bandwidth):资料通过IPC通道转移的速度.为测量该值,我们从一个程序向另一个程序传送大量资料(几百万位元组).我们还给不同大小的I/O *** 作(例如管道和FIFO的write和read *** 作)测量该值,期待发现频宽随每个I/O *** 作的资料量的增长而增长返蚂的规律. 2. 延迟(latency):一个小的IPC讯息从一个程序到令一个程序再返回来所花的时间.我们测量的是只有一个1个位元组的讯息从一个程序到令一个程序再回来的时间(往返时间) 在现实世界中,频宽告诉我们大块资料通过一个IPC通道传送出去需花多长时间,然而IPC也用于传递小的控制资讯,系统处理这些小讯息所需的时间就由延迟提供.这两个数都很重要.

程序和执行绪的区别,程序间通讯方式有哪

程序间和执行绪间的协作区别:

程序互斥、同步的概念

程序互斥、同步的概念是并发程序下存在的概念,有了并发程序,就产生了资源的竞争与协作,从而就要通过程序的互斥、同步、通讯来解决资源的竞争与协作问题。

下面是根据《作业系统教程》3.1.4 中的介绍,整理的程序互斥、同步的概念。

在多道程式设计系统中,同一时刻可能有许多程序,这些程序之间存在两种基本关系:竞争关系和协作关系。

程序的互斥、同步、通讯都是基于这两种基本关系而存在的,为了解决程序间竞争关系(间接制约关系)而引入程序互斥;为了解决程序间松散的协作关系( 直接制约关系)而引入程序同步;为了解决程序间紧密的协作关系而引入程序通讯。

第一种是竞争关系

系统中的多个程序之间彼此无关,它们并不知道其他程序的存在,并且也不受其他程序执行的影响。例如,批处理系统中建立的多个使用者程序, 分时系统中建立的多个终端程序。由于这些程序共用了一套计算机系统资源,因而, 必然要出现多个程序竞争资源的问题。当多个程序竞争共享硬装置、储存器、处理器 和档案等资源时,作业系统必须协调好程序对资枯世掘源的争用。

资源竞争出现了两个控制问题:一个是死锁 (deadlock )问题,一组程序如果都获得了部分资源,还想要得到其他程序所占有的资源,最终所有的程序将陷入死锁。另一个是饥饿(starvation )问题,这是指这样一种情况:一个程序由于其他程序总是优先于它而被无限期拖延。

作业系统需要保证诸程序能互斥地访问临界资源,既要解决饥饿问题,又要解决死锁问题。

程序的互斥(mutual exclusion )是解决程序间竞争关系( 间接制约关系) 的手段。 程序互斥指若干个程序要使用同一共享资源时,任何时刻最多允许一个程序去使用,其他要使用该资源的程序必须等待,直到占有资源的程序释放该资源。

第二种是协作关系

某些程序为完成同一任务需要分工协作,由于合作的每一个程序都是独立地以不可预知的速度推进,这就需要相互协作的程序在某些协调点上协 调各自的工作。当合作程序中的一个到达协调点后,在尚未得到其伙伴程序发来的讯息或讯号之前应阻塞自己,直到其他合作程序发来协调讯号或讯息后方被唤醒并继续执行。这种协作程序之间相互等待对方讯息或讯号的协调关系称为程序同步。

程序间的协作可以是双方不知道对方名字的间接协作,例如,通过共享访问一个缓冲区进行松散式协作;也可以是双方知道对方名字,直接通过通讯机制进行紧密协作。允许程序协同工作有利于共享资讯、有利于加快计算速度、有利于实现模组化程式设计。

程序的同步(Synchronization)是解决程序间协作关系( 直接制约关系) 的手段。程序同步指两个以上程序基于某个条件来协调它们的活动。一个程序的执行依赖于另一

个协作程序的讯息或讯号,当一个程序没有得到来自于另一个程序的讯息或讯号时则需等待,直到讯息或讯号到达才被唤醒。

不难看出,程序互斥关系是一种特殊的程序同步关系,即逐次使用互斥共享资源,也是对程序使用资源次序上的一种协调。

列举linux程序间通讯方式,linux pthread执行绪同步的方式有哪些

程序间通讯程序间通讯就是不同程序之间传播或交换资讯,程序的使用者空间是互相独立的,程序之间可以利用系统空间交换资讯。 管道(pipe)管道是一种半双工的通讯方式,资料只能单向流动。如果要进行双工通讯,需要建立两个管道。 管道只能在具有亲...

要传输大约1MB的资料,应该用哪种程序间通讯方式最佳

Simpson and Sons

54 Madison Street

Sydney, Australia.

7th November 2008

Dear Person-in-charge,

Re: Amendments of L/C No. 5058

We are writing to amend L/C No. 5058 of 3,000 dozens of Poplin Shirts as follows:

1) The beneficiary pany should be Pacific Trading Co., Ltd as opposed to Oriental Trading Co., Ltd.

2) The credit terms should be cash on delivery instead of 60 days credit terms.

3) The trade term or price term should be CFRC3 Marseilles in instead of CFR Marseilles.

4) The total transaction amount should be USD 300,000.00 and not GBP 300,000.00.

We apologized for any inconvenience caused. Please kindly make the following amendments as soon as possible and do not hesitate to contact me at xxx-xxxx-xxxx should you required further information.

Thank you.

Yours truly,

XXX

程序间同步是程序间通讯吗

管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系程序间的通讯,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系程序间的通讯讯号(Signal):讯号是比较复杂的通讯方式,用于通知接受程序有某种事件发生,除了用于程序间通讯外,程序还可以传送讯号给程序本身linux除了支援Unix早期讯号语义函式sigal外,还支援语义符合Posix.1标准的讯号函式sigaction(实际上,该函式是基于BSD的,BSD为了实现可靠讯号机制,又能够统一对外介面,用sigaction函式重新实现了signal函式)报文(Message)伫列(讯息伫列):讯息伫列是讯息的连结表,包括Posix讯息伫列system V讯息伫列。有足够许可权的程序可以向伫列中新增讯息,被赋予读许可权的程序则可以读走伫列中的讯息。讯息伫列克服了讯号承载资讯量少,管道只能承载无格式位元组流以及缓冲区大小受限等缺点。 共享记忆体:使得多个程序可以访问同一块记忆体空间,是最快的可用IPC形式。是针对其他通讯机制执行效率较低而设计的。往往与其它通讯机制,如讯号量结合使用,来达到程序间的同步及互斥。 讯号量(semaphore):主要作为程序间以及同一程序不同执行绪之间的同步手段。 套介面(Socket):更为一般的程序间通讯机制,可用于不同机器之间的程序间通讯。

程序间通讯方式中一般公司用的最多的是哪几个?做嵌入式的

pipe, fifo, 讯息伫列,共享记忆体这些传统的程序间通讯方式公司一般都不用,虽然共享记忆体可能快一点点,但是带来的维护开销等是很大的,公司一般会用socket也就是网路通讯的方式,或者是用资料库,程序1写资料库,程序2去读。我说的是linux系统。

python程序间通讯怎么理解

在2.6才开始使用

multiprocessing 是一个使用方法类似threading模组的程序模组。允许程式设计师做并行开发。并且可以在UNIX和Windows下执行。

通过建立一个Process 型别并且通过呼叫call()方法spawn一个程序。

一个比较简单的例子:

#!/usr/bin/env python

from multiprocessing import Process

import time

def f(name):

time.sleep(1)

print 'hello ',name

print os.getppid() #取得父程序ID

print os.getpid() #取得程序ID

process_list = []

if __name__ == '__main__':

for i in range(10):

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

p.start()

process_list.append(p)

for j in process_list:

j.join()

程序间通讯:

有两种主要的方式:Queue、Pipe

1- Queue类几乎就是Queue.Queue的复制,示例:

#!/usr/bin/env python

from multiprocessing import Process,Queue

import time

def f(name):

time.sleep(1)

q.put(['hello'+str(name)])

process_list = []

q = Queue()

if __name__ == '__main__':

for i in range(10):

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

p.start()

process_list.append(p)

for j in process_list:

j.join()

for i in range(10):

print q.get()

2- Pipe 管道

#!/usr/bin/env python

from multiprocessing import Process,Pipe

import time

import os

def f(conn,name):

time.sleep(1)

conn.send(['hello'+str(name)])

print os.getppid(),'-----------',os.getpid()

process_list = []

parent_conn,child_conn = Pipe()

if __name__ == '__main__':

for i in range(10):

p = Process(target=f,args=(child_conn,i))

p.start()

process_list.append(p)

for j in process_list:

j.join()

for p in range(10):

print parent_conn.recv()

Pipe()返回两个连线类,代表两个方向。如果两个程序在管道的两边同时读或同时写,会有可能造成corruption.

程序间同步

multiprocessing contains equivalents of all the synchronization primitives from threading.

例如,可以加一个锁,以使某一时刻只有一个程序print

#!/usr/bin/env python

from multiprocessing import Process,Lock

import time

import os

def f(name):

lock.acquire()

time.sleep(1)

print 'hello--'+str(name)

print os.getppid(),'-----------',os.getpid()

lock.release()

process_list = []

lock = Lock()

if __name__ == '__main__':

for i in range(10):

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

p.start()

process_list.append(p)

for j in process_list:

j.join()

程序间共享状态 Sharing state beeen processes

当然尽最大可能防止使用共享状态,但最终有可能会使用到.

1-共享记忆体

可以通过使用Value或者Array把资料储存在一个共享的记忆体表中

#!/usr/bin/env python

from multiprocessing import Process,Value,Array

import time

import os

def f(n,a,name):

time.sleep(1)

n.value = name * name

for i in range(len(a)):

a[i] = -i

process_list = []

if __name__ == '__main__':

num = Value('d',0.0)

arr = Array('i',range(10))

for i in range(10):

p = Process(target=f,args=(num,arr,i))

p.start()

process_list.append(p)

for j in process_list:

j.join()

print num.value

print arr[:]

输出:

jimin@Jimin:~/projects$ python pp.py

81.0

[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

'd'和'i'引数是num和arr用来设定型别,d表示一个双精浮点型别,i表示一个带符号的整型。

更加灵活的共享记忆体可以使用multiprocessing.sharectypes模组

Server process

Manager()返回一个manager型别,控制一个server process,可以允许其它程序通过代理复制一些python objects

支援list,dict,Namespace,Lock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value,Array

例如:

#!/usr/bin/env python

from multiprocessing import Process,Manager

import time

import os

def f(d,name):

time.sleep(1)

d[name] = name * name

print d

process_list = []

if __name__ == '__main__':

manager = Manager()

d = manager.dict()

for i in range(10):

p = Process(target=f,args=(d,i))

p.start()

process_list.append(p)

for j in process_list:

j.join()

print d

输出结果:

{2: 4}

{2: 4, 3: 9}

{2: 4, 3: 9, 4: 16}

{1: 1, 2: 4, 3: 9, 4: 16}

{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 8: 64}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

Server process managers比共享记忆体方法更加的灵活,一个单独的manager可以被同一网路的不同计算机的多个程序共享。

比共享记忆体更加的缓慢

使用工作池 Using a pool of workers

Pool类代表 a pool of worker processes.

It has methods which allows tasks to be offloaded to the worker processes in a few different ways.

c#多执行绪之间通讯方式有几种

多执行绪通讯的方法主要有以下三种: 1.全域性变数 程序中的执行绪间记忆体共享,这是比较常用的通讯方式和互动方式。 注:定义全域性变数时最好使用volatile来定义,以防编译器对此变数进行优化。 2.Message讯息机制 常用的Message通讯的介面主要有两个

windows程序间通讯和linux相同吗

# 管道( pipe ):管道是一种半双工的通讯方式,资料只能单向流动,而且只能在具有亲缘关系的程序间使用。程序的亲缘关系通常是指父子程序关系。 # 有名管道 (named pipe) : 有名管道也是半双工的通讯方式,但是它允许无亲缘关系程序间的通讯。

使用Python中的线程模块,能够同时运行程序的不同部分,并简化设计。如果你已经入门Python,并且想用线程来提升程序运行速度的话,希望这篇教程会对你有所帮助。

线程与进程

什么是进程

进程是系统进行资源分配和调度的一个独立单位 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

什么是线程

CPU调度和分派的基本单位 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

进程与线程的关系图

线程与进程的区别:

进程

现实生活中,有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶 汽车 ,比如唱歌跳舞也是同时进行的,再比如边吃饭边打电话;试想如果我们吃饭的时候有一个领导来电,我们肯定是立刻就接听了。但是如果你吃完饭再掘册接听或者回电话,很可能会被开除。

注意:

多任务的概念

什么叫 多任务 呢?简单地说,就是 *** 作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只陪友是桌面上没有显示而已。

现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码判乱宏都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?

答案就是 *** 作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒,这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。

真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以, *** 作系统也会自动把很多任务轮流调度到每个核心上执行。 其实就是CPU执行速度太快啦!以至于我们感受不到在轮流调度。

并行与并发

并行(Parallelism)

并行:指两个或两个以上事件(或线程)在同一时刻发生,是真正意义上的不同事件或线程在同一时刻,在不同CPU资源呢上(多核),同时执行。

特点

并发(Concurrency)

指一个物理CPU(也可以多个物理CPU) 在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。

特点

multiprocess.Process模块

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

语法:Process([group [, target [, name [, args [, kwargs]]]]])

由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)。

注意:1. 必须使用关键字方式来指定参数;2. args指定的为传给target函数的位置参数,是一个元祖形式,必须有逗号。

参数介绍:

group:参数未使用,默认值为None。

target:表示调用对象,即子进程要执行的任务。

args:表示调用的位置参数元祖。

kwargs:表示调用对象的字典。如kwargs = {'name':Jack, 'age':18}。

name:子进程名称。

代码:

除了上面这些开启进程的方法之外,还有一种以继承Process的方式开启进程的方式:

通过上面的研究,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题。

当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题,我们可以考虑加锁,我们以模拟抢票为例,来看看数据安全的重要性。

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改。加锁牺牲了速度,但是却保证了数据的安全。

因此我们最好找寻一种解决方案能够兼顾:1、效率高(多个进程共享一块内存的数据)2、帮我们处理好锁问题。

mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。队列和管道都是将数据存放于内存中 队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来, 我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性( 后续扩展该内容 )。

线程

Python的threading模块

Python 供了几个用于多线程编程的模块,包括 thread, threading 和 Queue 等。thread 和 threading 模块允许程序员创建和管理线程。thread 模块 供了基本的线程和锁的支持,而 threading 供了更高级别,功能更强的线程管理的功能。Queue 模块允许用户创建一个可以用于多个线程之间 共享数据的队列数据结构。

python创建和执行线程

创建线程代码

1. 创建方法一:

2. 创建方法二:

进程和线程都是实现多任务的一种方式,例如:在同一台计算机上能同时运行多个QQ(进程),一个QQ可以打开多个聊天窗口(线程)。资源共享:进程不能共享资源,而线程共享所在进程的地址空间和其他资源,同时,线程有自己的栈和栈指针。所以在一个进程内的所有线程共享全局变量,但多线程对全局变量的更改会导致变量值得混乱。

代码演示:

得到的结果是:

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行(其中的JPython就没有GIL)。

那么CPython实现中的GIL又是什么呢?GIL全称Global Interpreter Lock为了避免误导,我们还是来看一下官方给出的解释:

主要意思为:

因此,解释器实际上被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。在多线程环境中,Python 虚拟机按以下方式执行:

由于GIL的存在,Python的多线程不能称之为严格的多线程。因为 多线程下每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程在运行。

由于GIL的存在,即使是多线程,事实上同一时刻只能保证一个线程在运行, 既然这样多线程的运行效率不就和单线程一样了吗,那为什么还要使用多线程呢?

由于以前的电脑基本都是单核CPU,多线程和单线程几乎看不出差别,可是由于计算机的迅速发展,现在的电脑几乎都是多核CPU了,最少也是两个核心数的,这时差别就出来了:通过之前的案例我们已经知道,即使在多核CPU中,多线程同一时刻也只有一个线程在运行,这样不仅不能利用多核CPU的优势,反而由于每个线程在多个CPU上是交替执行的,导致在不同CPU上切换时造成资源的浪费,反而会更慢。即原因是一个进程只存在一把gil锁,当在执行多个线程时,内部会争抢gil锁,这会造成当某一个线程没有抢到锁的时候会让cpu等待,进而不能合理利用多核cpu资源。

但是在使用多线程抓取网页内容时,遇到IO阻塞时,正在执行的线程会暂时释放GIL锁,这时其它线程会利用这个空隙时间,执行自己的代码,因此多线程抓取比单线程抓取性能要好,所以我们还是要使用多线程的。

GIL对多线程Python程序的影响

程序的性能受到计算密集型(CPU)的程序限制和I/O密集型的程序限制影响,那什么是计算密集型和I/O密集型程序呢?

计算密集型:要进行大量的数值计算,例如进行上亿的数字计算、计算圆周率、对视频进行高清解码等等。这种计算密集型任务虽然也可以用多任务完成,但是花费的主要时间在任务切换的时间,此时CPU执行任务的效率比较低。

IO密集型:涉及到网络请求(time.sleep())、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO *** 作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。

当然为了避免GIL对我们程序产生影响,我们也可以使用,线程锁。

Lock&RLock

常用的资源共享锁机制:有Lock、RLock、Semphore、Condition等,简单给大家分享下Lock和RLock。

Lock

特点就是执行速度慢,但是保证了数据的安全性

RLock

使用锁代码 *** 作不当就会产生死锁的情况。

什么是死锁

死锁:当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。即死锁是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。

所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。

死锁代码

python线程间通信

如果各个线程之间各干各的,确实不需要通信,这样的代码也十分的简单。但这一般是不可能的,至少线程要和主线程进行通信,不然计算结果等内容无法取回。而实际情况中要复杂的多,多个线程间需要交换数据,才能得到正确的执行结果。

python中Queue是消息队列,提供线程间通信机制,python3中重名为为queue,queue模块块下提供了几个阻塞队列,这些队列主要用于实现线程通信。

在 queue 模块下主要提供了三个类,分别代表三种队列,它们的主要区别就在于进队列、出队列的不同。

简单代码演示

此时代码会阻塞,因为queue中内容已满,此时可以在第四个queue.put('苹果')后面添加timeout,则成为 queue.put('苹果',timeout=1)如果等待1秒钟仍然是满的就会抛出异常,可以捕获异常。

同理如果队列是空的,无法获取到内容默认也会阻塞,如果不阻塞可以使用queue.get_nowait()。

在掌握了 Queue 阻塞队列的特性之后,在下面程序中就可以利用 Queue 来实现线程通信了。

下面演示一个生产者和一个消费者,当然都可以多个

使用queue模块,可在线程间进行通信,并保证了线程安全。

协程

协程,又称微线程,纤程。英文名Coroutine。

协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。

通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。

在实现多任务时,线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 *** 作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据, *** 作系统还会帮你做这些数据的恢复 *** 作。所以线程的切换非常耗性能。但是协程的切换只是单纯的 *** 作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

greenlet与gevent

为了更好使用协程来完成多任务,除了使用原生的yield完成模拟协程的工作,其实python还有的greenlet模块和gevent模块,使实现协程变的更加简单高效。

greenlet虽说实现了协程,但需要我们手工切换,太麻烦了,gevent是比greenlet更强大的并且能够自动切换任务的模块。

其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件 *** 作等) *** 作时,比如访问网络,就自动切换到其他的greenlet,等到IO *** 作完成,再在适当的时候切换回来继续执行。

模拟耗时 *** 作:

如果有耗时 *** 作也可以换成,gevent中自己实现的模块,这时候就需要打补丁了。

使用协程完成一个简单的二手房信息的爬虫代码吧!

以下文章来源于Python专栏 ,作者宋宋

文章链接:https://mp.weixin.qq.com/s/2r3_ipU3HjdA5VnqSHjUnQ


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12319937.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存