线程与事件循环 - 网络编程(语言不可知)

时间:2014-05-09 15:39:14

标签: python multithreading events twisted

我正在编写一个简单的守护进程来接收来自N个移动设备的数据。设备将轮询服务器并将其所需的数据作为简单的JSON发送。在通用术语中,服务器将接收数据,然后用它“做东西”。

我知道这个话题已被打过很多次,但我很难理解其优缺点。

就并发性和可伸缩性而言,线程或事件(在Python中认为Twisted)是否更适合这种情况?事件模型似乎更有意义,但我想轮询你们。数据进来 - >过程数据 - >等待更多数据。如果“做东西”是计算密集型的东西怎么办?如果“do stuff”非常密集(例如插入数据库),该怎么办?这会阻止事件循环吗?每种方法的优点和缺点是什么?

3 个答案:

答案 0 :(得分:5)

我只能在Python的背景下回答,因为那是我的大部分经历。根据您选择的语言,答案实际上可能略有不同。例如,Python在并行化I / O密集型操作方面比CPU密集型操作要好得多。

扭曲,龙卷风,gevent等异步编程库非常擅长并行处理大量I / O.如果您的工作负载涉及许多客户端连接,执行轻型CPU操作和/或大量I / O操作(如数据库读/写),或者您的客户端正在建立主要用于I / O的长期连接(想想WebSockets),然后一个异步库将非常适合您。大多数Python异步库都有流行数据库的异步驱动程序,因此您可以在不阻塞事件循环的情况下与它们进行交互。

如果您的服务器将要进行大量的CPU密集型工作,您仍然可以使用异步库,但必须了解每次进行CPU工作时,事件循环都将被阻止。没有其他客户能够做任何事情。但是,有办法解决这个问题。您可以使用线程/进程池来管理CPU工作,并且只是异步等待响应。但显然这会使你的实现变得复杂一点。

使用Python,使用线程实际上并不能通过CPU操作为您买单,因为在大多数情况下只有一个线程可以运行一段时间,因此您并没有真正获得拥有多核CPU(google" Python GIL"了解更多信息)。忽略线程中特定于Python的问题,线程将让您避免阻塞事件循环"完全问题,并且线程代码通常比异步代码更容易理解,特别是如果您不熟悉异步编程的工作方式。但是你还必须处理常见的线程问题(同步共享状态等),并且它们不会像许多客户端那样进行扩展以及异步I / O(参见http://en.wikipedia.org/wiki/C10k_problem

这两种方法在生产中都非常成功地使用,因此您需要更好地决定哪种方法适合您的需求/偏好。

答案 1 :(得分:3)

我认为您的问题属于'依赖'类别。

不同的语言在线程/进程/事件方面有不同的优点和缺点(python在与global interpreter lock绑定的线程中有一些特殊的弱点)

除此之外,当您查看进程与线程与事件时,操作系统也有不同的优缺点。 unix上的内容不会与windows相同。

话虽如此,我整理多方面IO项目的方式是:

  

这些项目很复杂,没有任何工具可以简单地消除复杂性,因此您有两种选择:

     
      
  1. 让操作系统处理尽可能多的复杂性,使程序员的生活更轻松,但代价是机器效率
  2.   
  3. 让程序员具有尽可能多的复杂性,以便他们能够优化设计并尽可能多地挤出机器,代价是需要更高端程序的更复杂的代码。
  4.         

    选项1通常最好通过将任务分解为每个线程/进程一个阻塞状态机的线程或进程来实现

         

    选项2通常最好通过将所有任务复用到一个进程并使用OS挂钩进行事件系统来完成。 (select / poll / epoll / kqueue / WaitForMultipleObjects / CoreFoundation / libevent等。)

根据我的经验,项目框架/ internal-arch经常归结为手头的程序员的技能(以及项目对硬件的预算)。

如果你有程序员在OS内部有背景:Twisted对python很有用,Node.js对Javascript很有用,libevent / libev对C或C ++很有用。你最终会得到可以轻松扩展的超高效代码,尽管你会有一个噩梦,试图聘请更多的程序员

如果您有新手程序员,并且可以将资金转入大量云服务,那么将项目分解为多个线程或流程将为您提供最佳工作机会,尽管扩展最终会成为一个问题。

总而言之,我会说多个迭代项目的最佳模式是在简单的阻塞工具(烧瓶)中进行原型设计,然后重新写入更难/更可扩展(扭曲)的东西,否则你会陷入困境经典Premature optimization is the root of all evil陷阱

答案 2 :(得分:0)

连接方案在选择中也很重要。您期望多少并发连接?客户保持联系多长时间?

如果每个连接都绑定到一个线程,那么许多并发连接或非常持久的连接(与websockets一样)将阻塞系统。对于这些场景,基于事件循环的解决方案将更好。

当连接很短并且在断开连接后进行重型处理时,两种型号都会相互称重。