V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ray1888
V2EX  ›  Python

Python 的 socket 多线程问题,求大神解答

  •  
  •   ray1888 ·
    ray1888 · 2017-06-13 22:33:20 +08:00 · 3411 次点击
    这是一个创建于 2754 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近开始搞 Python 的网络编程,在写 FTP 服务器。然后基础功能都可以了(项目的目录还没优化),但是不知道怎么使可以使得多个客户端接入,怎样添加多线程或多进程才能是项目可以支持多个客户端接入呢? https://github.com/ray1888/Python-socket-programming 项目地址在此,使用的是 server-connect-test.pyclient-connect-test.py 作为服务器端和客户端,如果有大神提一点建议,万分感谢

    18 条回复    2017-06-15 20:03:39 +08:00
    billlee
        1
    billlee  
       2017-06-13 22:56:11 +08:00
    这个问题和 python 一点关系都没有,去看 APUE 和 UNP
    misaka19000
        3
    misaka19000  
       2017-06-13 23:21:33 +08:00 via Android
    就用简单的每个链接开一个线程就行了
    noli
        4
    noli  
       2017-06-14 00:13:35 +08:00
    支持多个客户端并发接入根本不是靠多线程。
    当然,如果你说我一简单 FTP 服务器就那么几个用户,也不是不可以用多线程来实现。
    但是本质上来说是一个错误的做法,不要指望碰巧把事情做对。
    noli
        5
    noli  
       2017-06-14 00:21:40 +08:00
    有 gevent 用 gevent, 没有 gevent 用 tornado-ftp。
    用 python 的目的就是大量用库用框架解决这些问题,不然人生就苦短了。
    yxwzaxns
        6
    yxwzaxns  
       2017-06-14 00:26:43 +08:00 via iPhone
    好巧,我也在写
    github.com/yxwzaxns/cowry
    ryd994
        7
    ryd994  
       2017-06-14 02:13:24 +08:00 via Android
    看请求量吧,最简单开多线程
    复杂点的用 gevent 的 monkey patch 包一下,你这个情况应该不用额外处理
    用 select/epoll 才是正道
    AZLisme
        8
    AZLisme  
       2017-06-14 09:08:32 +08:00
    上异步吧,去看看 asyncio,如果你是用 python3
    ray1888
        9
    ray1888  
    OP
       2017-06-14 09:19:44 +08:00
    @AZLisme 我用的是 python3,如果上了 asyncio 还需要上多线程吗?
    ray1888
        10
    ray1888  
    OP
       2017-06-14 09:20:54 +08:00
    @noli 如果我用 Python3,gevent 和 asyncio 应该用哪一个来做协程?然后做了协程之后,还需要多开线程来处理吗?
    AZLisme
        11
    AZLisme  
       2017-06-14 09:41:44 +08:00   ❤️ 1
    @ray1888 一般而言上了异步就不需要多线程了。如果你 Python 3.5 +,我还是推荐 asyncio,它有对于 socket 的异步读写支持的,写起来应该很顺畅。
    ray1888
        12
    ray1888  
    OP
       2017-06-14 09:47:41 +08:00
    @AZLisme 那是否就是协程和多线程多进程不能并存吗?因为还是不太懂协程和多线程对于并发的区别。我目前所知的协程,是单个线程在不同时间内进行多个任务的执行,等待 await 返回的结果,如果同一程序多线程或多进程,就是相当于可以同时处理多个请求,但是程序是线性运行
    AZLisme
        13
    AZLisme  
       2017-06-14 09:56:47 +08:00
    @ray1888 实际上可以并存!所以我刚才说的是「一般而言上了异步就不需要多线程了」

    协程是异步编程一种方法,总的来说它不是传统的线性运行,在某一个局部代码块的层面上它是线性运行,不会中断的(所以不太需要锁)。但是整体来看,它的运行顺序是不确定的。

    更加具体的来说,这个线程上会运行一个 EventLoop,然后选择代码块执行;某一个代码块执行到某一个地方,会主动放弃自己的执行权( yield 或 await )保存住状态,直到指定的事件被触发。这个执行权必须是主动放弃的,EventLoop 不会强制中断。放弃执行权之后,EventLoop 就会挑选下一个可以被执行的块来执行,或者有被监听的的事件发生,就会通知之前主动中断的协程继续执行。
    noli
        14
    noli  
       2017-06-14 10:25:15 +08:00
    @ray1888

    通常而言,asyncio 和 gevent 只选一个。
    我也没试过混搭,两个事件循环一起用,应该会有诡异的 bug。

    等你用这两者其中一个之后遇到瓶颈再考虑多线程吧。
    我的观察是,你还要学习一下才能驾驭多线程吧。
    ray1888
        15
    ray1888  
    OP
       2017-06-14 22:28:25 +08:00
    @noli 大神有好的 ASYNCIO 的模块教程或者项目推荐给我看吗?我看廖雪峰那个教程还是有点不太懂
    noli
        16
    noli  
       2017-06-15 01:59:09 +08:00
    @ray1888

    我也不知道什么样的教程是我懂你也懂的。
    所以哪里不懂你就开帖问,请用心努力吧。
    ray1888
        17
    ray1888  
    OP
       2017-06-15 20:02:30 +08:00
    @noli 你好
    ray1888
        18
    ray1888  
    OP
       2017-06-15 20:03:39 +08:00
    @noli 为什么我这段代码还是会报错,他说我并没有协程,但是我不知道问题在哪个地方
    import socket
    import asyncio

    def waiting(sock):
    sock.listen(5)
    sock_acc, addr = sock.accept()
    return sock_acc

    async def sendhello(sendsock):
    sendsock.send(b'100')
    remote = sendsock.getsockname()
    print("{} is connect".format(remote[0]))

    async def createsock():
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('0.0.0.0', 8999))
    sock_acc = waiting(sock)
    await sendhello(sock_acc)


    if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    #task = [createsock() for i in range(5)]
    #loop.run_until_complete(task)
    task = [createsock(), createsock()]
    loop.run_until_complete(task)
    loop.close()

    报错是这样的
    sys:1: RuntimeWarning: coroutine 'createsock' was never awaited
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2759 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:43 · PVG 17:43 · LAX 01:43 · JFK 04:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.