Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa中的并发网络客户端_Cocoa_Architecture_Networking_Concurrency_Grand Central Dispatch - Fatal编程技术网

Cocoa中的并发网络客户端

Cocoa中的并发网络客户端,cocoa,architecture,networking,concurrency,grand-central-dispatch,Cocoa,Architecture,Networking,Concurrency,Grand Central Dispatch,我正试图在我的头脑中找到一种构造Cocoa应用程序的最佳方法,它本质上是一个并发下载管理器。有一个应用程序与之对话的服务器,用户列出一个大列表,应用程序处理该列表。(它不使用HTTP或FTP,因此我无法使用URL加载系统;我将通过套接字连接进行交谈。) 这基本上是经典的生产者-消费者模式。诀窍在于消费者的数量是固定的,而且他们是持久的。服务器对可以同时打开的连接数设置了严格限制(尽管通常至少两个),并且打开新连接的费用很高,因此在理想情况下,相同的N个连接在应用程序的生命周期内都是打开的 一种方

我正试图在我的头脑中找到一种构造Cocoa应用程序的最佳方法,它本质上是一个并发下载管理器。有一个应用程序与之对话的服务器,用户列出一个大列表,应用程序处理该列表。(它不使用HTTP或FTP,因此我无法使用URL加载系统;我将通过套接字连接进行交谈。)

这基本上是经典的生产者-消费者模式。诀窍在于消费者的数量是固定的,而且他们是持久的。服务器对可以同时打开的连接数设置了严格限制(尽管通常至少两个),并且打开新连接的费用很高,因此在理想情况下,相同的N个连接在应用程序的生命周期内都是打开的

一种方法是创建N个线程,每个线程“拥有”一个连接,并在请求队列上等待,如果请求队列为空则阻塞。由于连接的数量永远不会很大,因此就实际系统开销而言,这并非不合理。但从概念上讲,可可必须提供一个更优雅的解决方案

似乎我可以使用,然后调用
setMaxConcurrentOperationCount:
,并显示连接数。然后我就把下载请求扔进那个队列。但我不确定,在这种情况下,如何管理连接本身。(只需将它们放在堆栈上,并依靠队列确保我不会跑得太多/太少?在堆栈中加入一个?)

现在,我们进入了一个勇敢的新世界,这是否为解决这一问题开辟了其他途径?乍一看,似乎不是这样,因为GCD动态扩展并发性的旗舰功能(在苹果的建议中提到)实际上对我没有帮助。但我只是初步了解了这方面的情况

编辑:


如果有关系:是的,我计划使用异步/非阻塞套接字API与服务器进行实际通信。因此,I/O本身不必位于自己的线程上。我只关心排队工作的机制,以及(安全地)在连接可用时将其分配给连接。

如果使用CFSocket的非阻塞调用进行I/O,我同意,这一切都应该发生在主线程上,让操作系统处理并发问题,因为您只是复制数据,而不是真正进行任何计算

除此之外,你的应用程序需要做的唯一其他工作就是维护一个要下载的项目队列。当任何一个传输完成时,CFSocket回调可以启动队列上下一个项目的传输。(如果队列为空,则减少连接计数,如果向空队列添加了内容,则开始新的传输。)我不明白为什么需要多个线程

也许你遗漏了一些重要的东西,但是根据你的描述,这个应用程序是I/O绑定的,而不是CPU绑定的,所以所有并发性的东西只会使代码更加复杂,对性能的影响最小


这一切都在主线上进行。

为了子孙后代的利益,在其他地方进行了一些讨论之后,我认为我会为此采取的解决方案基本上是:

  • 有一个挂起的下载操作队列,初始为空
  • 有一个包含所有打开连接的集合,最初为空
  • 有一个可变的空闲开放连接数组(实际上是队列),初始为空
  • 当用户添加下载请求时:
    • 如果空闲连接阵列不是空的,请删除一个并将下载分配给它
    • 如果没有空闲连接,但总连接数未达到其限制,请打开一个新连接,将其添加到集合中,并将下载分配给它
    • 否则,请将下载排队等待以后
  • 下载完成时:如果有排队的请求,则将一个请求出列 并将其交给连接;否则,将连接添加到空闲列表
所有这些工作都将在主线程上进行。解码每次下载结果的工作将被卸载到GCD,这样它就可以处理并发限制,并且不会阻塞主线程


打开一个新连接可能需要一段时间,因此在实际操作中创建一个新连接的过程可能会稍微复杂一些(例如,将下载排队,启动连接过程,然后在连接完全建立后将其出列)。但我仍然认为我对比赛条件可能性的看法被夸大了。

该应用程序几乎肯定不受CPU限制。下载完成后会有一些解码任务,但我可以把它们发送给GCD处理。我主要关心的是1)保持UI的响应性,以及2)在排队工作中避免任何竞争条件。如果I/O回调都在主线程上运行,这通常可以解决(2),但我想知道这样做是否以(1)为代价。据推测,这项工作的大部分只是将内容添加到缓冲区,而且应该非常快。