资讯专栏INFORMATION COLUMN

【tulip】 - 多线程的版本

CoderStudy / 1189人阅读

摘要:最重要的是每个线程,对应了一个函数的执行。有多个线程同时执行的时候,每个线程的状态是由操作系统内核负责保存在内存中的。在多线程的实现中。并且内核的线程在切换多个线程的时候,线程切换的开销是比较大。

上次的网络编程的例子,改写成多线程的是这样:

import socket
import thread

def main():
    listen_sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=socket.IPPROTO_IP)
    listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listen_sock.bind(("0.0.0.0", 9090))
    listen_sock.listen(0)
    while True:
        conn_sock, client_addr = listen_sock.accept()
        thread.start_new(serve, (conn_sock, client_addr))

def serve(conn_sock, client_addr):
    print("connected from %s:%s" % client_addr)
    input = conn_sock.recv(8192)
    while "done" != input.strip():
        conn_sock.sendall(input)
        input = conn_sock.recv(8192)
    conn_sock.sendall("bye!
")
    conn_sock.close()

main()

变成多线程之后,就可以有多个客户端同时连接到服务器并同时进行服务了。最重要的是每个线程,对应了一个“serve”函数的执行。所以函数执行就是有一个函数的栈,栈上有一个函数的参数和局部变量。最重要的一个局部变量就是conn_sock,有了这个socket就可以和对应的客户端进行对话。
机器都有一个ESP的寄存器指向函数的栈顶所在的内存地址。一个cpu核只有一个ESP寄存器。有多个线程同时执行的时候,每个线程的状态是由操作系统内核负责保存在内存中的。当这个线程被调度为执行状态的时候,ESP寄存器被切换为当前线程的栈顶位置,然后继续执行这个线程的后面的指令。服务器可以支持多个客户端,就有两个关键的问题要解决:

保存每个客户端的服务状态(最起码要保存对应这个客户端的socket)

一个全局scheduler来负责I/O,在需要的时候把客户端对应的状态切换为“当前活跃”状态。在线程调用了阻塞的I/O操作时,操作系统内核就把线程给挂起了,同时在映射表里记录一个对应关系,哪个I/O阻塞的fd对应的是哪个线程在等待它。等I/O阻塞条件满足了,对应的线程就会被查表得到然后被唤醒。

在多线程的实现中。每个客户端的状态就是保存在线程对应函数的栈上的,而全局的scheduler就是内核的线程scheduler。这种实现方式最大的缺点是线程的栈是创建时预先分配的很大的一块区域,大量线程会耗费过度内存。并且内核的线程scheduler在切换多个线程的时候,线程切换的开销是比较大。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45305.html

相关文章

  • tulip】 - 进程版本

    摘要:前面的网络编程的例子使用多进程也是可以实现的其中之后会创建一个子进程。从效率上来说,具有多线程一样的问题,而且内存占用会更高,切换成本也更高。多线程和多进程的版本从代码可读性上来说还是非常不错的,很好懂,从上至下平铺直叙的。 前面的网络编程的例子使用多进程也是可以实现的: import socket import os def main(): listen_sock = s...

    ACb0y 评论0 收藏0
  • tulip】 - IOCP

    摘要:简单来说就是一个操作系统提供的回调机制。其中这一步是创建,是做一个调用,后面的是轮询,这一步是根据返回的查找对应的回调函数回调。这样状态从多个线程的多个栈上,变成了只有一个线程,但是在线程内部有一个来维护单线程内多个并发流程的状态。 为了让I/O阻塞的时候,程序还可以去干别的。除了使用线程模型,让操作系统的内核去调度多个线程,Windows提供了IOCP机制。简单来说就是一个操作系统提...

    Sunxb 评论0 收藏0
  • tulip】 - I/O阻塞小例子

    摘要:在了解了的实现方式的基础之上,希望能够把流程阻塞的功能在的框架之上实现,从而可以制作一个简单的类似,这样的集群调度工具。我们先来看一个最基本的网络编程的例子这是一个服务器。 接下来,会把Python tulip这个网络库(也就是3.4之后的asyncio)如何实现的进行一些分析。在了解了tulip的实现方式的基础之上,希望能够把流程阻塞的功能在tulip的框架之上实现,从而可以制作一个...

    JessYanCoding 评论0 收藏0
  • python并发2:使用asyncio处理并发

    摘要:是之后引入的标准库的,这个包使用事件循环驱动的协程实现并发。没有能从外部终止线程,因为线程随时可能被中断。上一篇并发使用处理并发我们介绍过的,在中,只是调度执行某物的结果。 asyncio asyncio 是Python3.4 之后引入的标准库的,这个包使用事件循环驱动的协程实现并发。asyncio 包在引入标准库之前代号 Tulip(郁金香),所以在网上搜索资料时,会经常看到这种花的...

    wushuiyong 评论0 收藏0
  • 【generator101】 - yield from

    摘要:我们可以看一下的可见是由内部支持的,其实现原理上就避免了栈进栈出的消耗,直接由最内层的返回值。另外可以实现外部直接向最内层的传递值,比如这段代码的输出是这样传值的方式,在用循环重新的模式下是无法实现的。这也就是必须使用,而不能使用的原因。 在python 3.3里,generator新增了一个语法 yield from 这个yield from的作用是什么?看下面两段对比的代码: d...

    xiaodao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<