网络与多任务基础知识

网络与多任务基础知识

简述 OSI 七层协议

1、物理层

主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

2、数据链路层

定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。

3、网络层

在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。

4、传输层

定义了一些传输数据的协议和端口号(WWW端口80等),如:
TCP(transmission control protocol –传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据)
UDP(user datagram protocol–用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。

5、会话层

通过运输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)

6、表示层

可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。

7、应用层

是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。

什么是C/S和B/S架构?

C/S

客户端/服务器的模型。要制作独立的客户端

B/S
浏览器/服务器的模型。只需要适配浏览器就可以了

简述 三次握手、四次挥手的流程。


所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:

  1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  3. 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

4次挥手(Four-Way Wavehand)

即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

  1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

什么是arp协议?

arp 是根据IP地址获取物理地址的一个TCP/IP协议,应用于交换机上

TCP和UDP的区别?

Tcp
– 可靠,长连接
– 数据包大
– 数据包有序
– 有流量控制和拥塞控制
– tcp只能单播,不能发送广播和组播

UDP
– 不可靠
– 数据包小
– 数据包无序
– 无流量控制和拥塞控制
– udp可以广播和组播

什么是局域网和广域网?

可以这样理解有一定管理范围的并且内部设备均是私有的范围外设备不能直接连通的范围叫做局域网
没有限定范围,可以互相通信。在网络里可见的就是广域网

为何基于tcp协议的通信比基于udp协议的通信更可靠?

在TCP协议中使用了接收确认和重传机制。这样每一次信息的传输都经过了像三次握手那样的一个过程,使得每一个信息都能保证到达,是可靠的。

而UDP是尽力传送,没有应答和重传机制,UDP只是将信息发送出去,对方收不收到也不进行应答。所以UDP协议是不可靠的。

什么是socket?简述基于tcp协议的套接字通信流程。

socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过”套接字”向网络发出请求或者应答网络请求。

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

socket和file的区别:

file模块是针对某个指定文件进行【打开】【读写】【关闭】

socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】image

服务端:创建socket对象,绑定ip端口bind(), 设置最大链接数listen(), accept()与客户端的connect()创建双向管道, send(), recv(),close()

客户端:创建socket对象,connect()与服务端accept()创建双向管道 , send(), recv(),close()

什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

缓存区有 第一次的文件大小和第二个文件的1024数据 都发到了服务端

增加确认数据 类似tcp的确认包之后再传输数据

IO多路复用的作用?

I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

什么是防火墙以及作用?

就是用来检查审计并且过滤异常请求。

select、poll、epoll 模型的区别?

Linux中的 select,poll,epoll 都是IO多路复用的机制。

select

select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。

poll

poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。

epoll

直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。
另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

简述 进程、线程、协程的区别 以及应用场景?

1、进程

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

2、线程

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

3、协程

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

1、多进程一般使用multiprocessing库,来利用多核CPU,主要是用在CPU密集型的程序上,当然生产者消费者这种也可以使用。多进程的优势就是一个子进程崩溃并不会影响其他子进程和主进程的运行,但缺点就是不能一次性启动太多进程,会严重影响系统的资源调度,特别是CPU使用率和负载。使用多进程可以查看文章《python 多进程使用总结》。注:python2的进程池在类中的使用会有问题,需要把类函数定义成全局函数。具体可参考 http://bbs.chinaunix.net/thread-4111379-1-1.html

2、多线程一般是使用threading库,完成一些IO密集型并发操作。多线程的优势是切换快,资源消耗低,但一个线程挂掉则会影响到所有线程,所以不够稳定。现实中使用线程池的场景会比较多,具体可参考《python线程池实现》。

3、协程一般是使用gevent库,当然这个库用起来比较麻烦,所以使用的并不是很多。相反,协程在tornado的运用就多得多了,使用协程让tornado做到单线程异步,据说还能解决C10K的问题。所以协程使用的地方最多的是在web应用上。

总结一下就是IO密集型一般使用多线程或者多进程,CPU密集型一般使用多进程,强调非阻塞异步并发的一般都是使用协程,当然有时候也是需要多进程线程池结合的,或者是其他组合方式。

Python中如何使用线程池和进程池?

Python 已经实现了进程池,线程池需要自己实现

进程池

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

进程池中有两个方法:
– apply 方法是阻塞的。
意思就是等待当前子进程执行完毕后,在执行下一个进程。
– apply_async 意思就是:不用等待当前进程执行完毕,随时根据系统调度来进行进程切换。

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,))
#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()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

#end
#100
#101
#102
#103
#104
#105
#106
#107
#108
#109

线程池

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import Queue
import threading


class ThreadPool(object):

    def __init__(self, max_num=20):
        self.queue = Queue.Queue(max_num)
        for i in xrange(max_num):
            self.queue.put(threading.Thread)

    def get_thread(self):
        return self.queue.get()

    def add_thread(self):
        self.queue.put(threading.Thread)

"""
pool = ThreadPool(10)

def func(arg, p):
    print arg
    import time
    time.sleep(2)
    p.add_thread()


for i in xrange(30):
    thread = pool.get_thread()
    t = thread(target=func, args=(i, pool))
    t.start()
"""

threading.local的作用?

threading.local()

这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,如果你在开发多线程应用的时候 需要每个线程保存一个单独的数据供当前线程操作,可以考虑使用这个方法,简单有效。举例:每个子线程使用全局对象a,但每个线程定义的属性a.xx是该线程独有的,Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。

import threading

# class Foo(object):
#     def __init__(self):
#         self.name =0

local_values = threading.local()
#local_values = Foo()

def func(num):
    local_values.name = num
    import time
    time.sleep(1)
    print(local_values.name,threading.current_thread().name)

for i in range(20):
    th = threading.Thread(target=func,args=(i,),name="线程%s"%i)
    th.start()

1 线程1
2 线程2
12 线程12
0 线程0
17 线程17
19 线程19
8 线程8
11 线程11
3 线程3
7 线程7
14 线程14
9 线程9
4 线程4
13 线程13
6 线程6
10 线程10
16 线程16
15 线程15
5 线程5
18 线程18

方法2 就是线程锁

https://morvanzhou.github.io/tutorials/python-basic/threading/6-lock/

lock.acquire()

lock.release()

import threading

def job1():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=1
        print('job1',A)
    lock.release()

def job2():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=10
        print('job2',A)
    lock.release()

if __name__== '__main__':
    lock=threading.Lock()
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

进程之间如何进行通信?

进程间通信主要包括管道,系统IPC(包括消息队列,信号,共享存储),套接字(SOCKET).

管道包括三种:
– 普通管道PIPE, 通常有两种限制,一是单工,只能单向传输;二是只能在父子或者兄弟进程间使用.
– 流管道s_pipe: 去除了第一种限制,为半双工,可以双向传输.
– 命名管道:name_pipe, 去除了第二种限制,可以在许多并不相关的进程之间进行通讯.

什么是并发和并行?

顺序执行:同一时间只能接受一件事情,而且只能处理这一件事情

并发:同一时间能接受多件事情,但是处理事情只能一件一件来

并行:同一时间能接受多件事情,而且能同时处理这些事情

解释什么是异步非阻塞?

阻塞:是指在处理一件事的时候不能接受其他任务。其他任务会被挂起等待

异步:是说可以把需要等待的事件放到后台执行。不会影响新任务的等待

所以说综合二者就是异步非阻塞将需要耗时执行的任务通过后台执行后在回调结果。不会因为耗时任务而阻塞新任务请求

同步异步指的是在客户端

同步意味着客户端提出了一个请求以后,在回应之前只能等待
异步意味着 客户端提出一个请求以后,还可以继续提其他请求阻塞

非阻塞 指的是服务器端

阻塞意味着服务器接受一个请求后,在返回结果以前不能接受其他请求
非阻塞意味着服务器接受一个请求后,尽管没有返回结果,还是可以继续接受其他请求

路由器和交换机的区别?

交换机工作于数据链路层,用来隔离冲突域,连接的所有设备同属于一个广播域(子网),负责子网内部通信。

路由器工作于网络层,用来隔离广播域(子网),连接的设备分属不同子网,工作范围是多个子网之间,负责网络与网络之间通信。

https://www.zhihu.com/question/20465477

进程锁和线程锁的作用?

进程锁

也是为了控制同一操作系统中多个进程访问一个共享资源,
只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,

线程锁

多线程可以同时运行多个任务但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误! so,不使用线程锁, 可能导致错误

当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。
当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的

什么是域名解析?

域名解析就是把人方便记的域名地址如www.baidu.com转换成IP地址

如何修改本地hosts文件?

linux或macos下 编辑/etc/hosts文件

#每一条ip对应一条解析
127.0.0.1   localhost 

windows下C:\WINDOWS\system32\drivers\etc\hosts文件

生产者消费者模型应用场景及优势?

生产者消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

http://www.cnblogs.com/huchong/p/7454756.html

什么是cdn?

cdn 内容分发网络 就是将网站的内容分发到靠近请求者的服务器上。一般只有大型云计算公司来提供服务

LVS是什么及作用?

LVS也叫做Linux虚拟服务器(Linux Virtual Server)创始人-章文嵩,是一个虚拟的四层交换器集群系统,根据目标地址和目标端口实现用户请求转发,本身不产生流量,只做用户请求转发,目前是负载均衡性能最好的集群系统。

Nginx是什么及作用?

nginx是一个高性能的HTTP和反向代理服务器,其特点是占用内存少,并发能力强.

  • 用做web服务器
  • 用做负载均衡
  • 用作反向代理服务

keepalived是什么及作用?

https://baike.baidu.com/item/Keepalived/10346758?fr=aladdin

Keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中。

haproxy是什么以及作用?

https://baike.baidu.com/item/haproxy/5825820

HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。

HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。

HAProxy运行在时下的硬件上,完全可以支持数以万计的 并发连接。

并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

什么是负载均衡?

负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

什么是rpc及应用场景?

rpc 远程过程调用
远程过程调用就是一种在两个原本相互独立的进程间建立一种类似于单个程序内函数间调用的函数调用机制。这样,不仅一个程序内的函数可以相互调用,不同程序间的函数也可以相互调用了。 至于用途,你可以从程序内函数调用的用途出发进行思考。首先是可以直接利用别的程序的部分功能,这是最基础的。更重要的,利用rpc可以实现系统的分布式架构,一方面有些功能比较相关应该放到一起实现,一方面物理因素的原因要求系统分解为多机实现,因此有的功能实现为了一个机器上的进程,而另外的功能实现为在另外机器上的进程,这两个进程间的协同和信息交互就可以通过rpc来实现。 另外,有些现成系统所设计的扩展方式就是要通过rpc实现,这时你就需要通过它所选择的rpc协议编程方式对原系统进行功能扩展

简述 asynio模块的作用和应用场景。

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,
然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

import time
import asyncio

#这个只是计时用的
now = lambda : time.time()

async def do_some_work(x):
    print("waiting:", x)

start = now()
# 这里是一个协程对象,这个时候do_some_work函数并没有执行
coroutine = do_some_work(2)
print(coroutine)#<coroutine object do_some_work at 0x102dffa40>
#  创建一个事件loop
loop = asyncio.get_event_loop()
# 将协程加入到事件循环loop
#run_until_complete方法将协程包装成为了一个任务(task)对象
loop.run_until_complete(coroutine)

print("Time:",now()-start)

https://www.cnblogs.com/zhaof/p/8490045.html

简述 gevent模块的作用和应用场景。

https://www.cnblogs.com/zcqdream/p/6196040.html

twisted框架的使用和应用?

http://www.cnblogs.com/zhiyong-ITNote/p/7360442.html

多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

#本样例探讨进程、线程、和协程区别
from multiprocessing import Process,Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

def write1(tlist):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to list...' % value)
        tlist.append(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read1(tlist):
    print('Process to read: %s' % os.getpid())
    while True:
        value = tlist
        print('Get %s from list.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    t = []
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # pw = Process(target=write1, args=(t,))
    # pr = Process(target=read1, args=(t,))
    #不同进程之间变量不能通讯需要使用Queue
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

asycio和gevent的区别是什么

手动挡和自动挡

asycio 需要自己在代码中让出CPU,控制权在自己手上
gevent 用会替换标准库,你以为调用的是标准库的方法实际已经被替换成gevent自己的实现,遇到阻塞调用,gevent会自动让出CPU

发表评论

电子邮件地址不会被公开。 必填项已用*标注