Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.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
Swift 在使用GCD时,当变量复制到func参数时感到困惑_Swift_Grand Central Dispatch_Dispatch - Fatal编程技术网

Swift 在使用GCD时,当变量复制到func参数时感到困惑

Swift 在使用GCD时,当变量复制到func参数时感到困惑,swift,grand-central-dispatch,dispatch,Swift,Grand Central Dispatch,Dispatch,我只是在学习Swift,并且正在研究一些CPU密集型任务的Grand Central Dispatch(GCD)。以下是(我相信)所有令我困惑的相关代码: // global declarations var digits = [Int]() // where the square's digits reside var perm_q = [[Int]]() // where we accumulate permutations to check later

我只是在学习Swift,并且正在研究一些CPU密集型任务的Grand Central Dispatch(GCD)。以下是(我相信)所有令我困惑的相关代码:

// global declarations
var digits        = [Int]()    // where the square's digits reside
var perm_q        = [[Int]]()  // where we accumulate permutations to check later
Let perm_q_max    = 1000       // how many permutations we queue before checking them
var enq_count     = 0          // how many times we've called check_squares
var N             = 3          // size of N x N square
let work_q = DispatchQueue.global()  // returns a global, concurrent dispatch queue
let work_g = DispatchGroup()         // returns a group we put all our work into

// func which is enqueued onto a GCD queue
func check_squares( cnt: Int, perm_ary: [[Int]]) { ... }

// func which calls enqueues check_squares() onto global GCD queue
func permute( k: Int, ary: inout [Int]) {

  if k == 1 {
    
    perm_q.append( ary)  // queue up this permutation for later magic checking

    // if we've queued up enough permutations, then dispatch check_squares()
    if ( perm_q.count >= perm_q_max) {
        enq_count += 1
        // --> let p: [[Int]] = perm_q  // make a local copy
        work_q.async( group: work_g) {      // assign work all to one group
        check_squares( cnt: enq_count,    // check to see if any square is magic
                       perm_ary: p)
      }
      perm_q = [[Int]]()                  // clear out previous permutations
    }
  }

  else { ... }
}

// main
    
digits = Array( 1 ... ( N * N))  // fill digits with digits 1...N^2
permute( k: digits.count, ary: &digits)  // creates permutations and checks for magic squares
我遇到的问题是,除非我在permute()中取消对work_q.async()上方的行的注释,否则当check_squares()开始时,ary有零个元素,而我希望它有1000个元素。在我将check_squres()排队到全局异步队列上的GCD之后,我立即执行perm_q=[Int],这将清空数组perm_q以准备收集接下来的1000个元素

我猜在开始check_squares()和清空perm_q之间存在竞争条件,清空发生在check_squares()开始之前,但我不明白为什么会发生这种竞争。我知道调用check_squares()将生成perm_q的副本

我想到的一种解释是,在GCD开始执行check_squares()之前,perm_q复制到check_squares()的参数中是不会发生的。当这种情况发生时,perm_q已被清空。这是当perm_q复制到ary时发生的,而不是当check_squares排队时发生的吗?将全局变量perm_q的本地副本设置为var p local to permute(),并在排队过程中将p传递给check_squares(),这会使局部变量p保持不变,因为队列中check_squares()的引用会使数组p即使在permute()退出后也不会消失。这听起来对吗

除了将perm_q的本地副本制作成p之外,还有更好的处理方法吗

谢谢,埃里克

除了制作本地副本…,还有更好的处理方法吗

为另一个线程提供其自己的本地副本的最简单方法是通过捕获列表:

queue.async(group: group).async { [array] in
    checkSquares(array)
}
除了制作本地副本…,还有更好的处理方法吗

为另一个线程提供其自己的本地副本的最简单方法是通过捕获列表:

queue.async(group: group).async { [array] in
    checkSquares(array)
}

与手头的问题无关,但在任何给定的时间,这些并发调用中有多少可能发生?工作线程的数量非常有限,这段代码看起来很可疑,它可能很容易导致线程爆炸,耗尽这些工作线程(在这一点上,您可能会有各种意外行为)。我们通常使用
concurrentPerform
来优化线程的利用率,尽管还有其他解决方案。但是要避免无限制的并发。我不知道你是如何保存结果的,但是要确保同步该操作(使用锁或它自己的同步队列)。如果您还没有完成,您可能需要运行此过程。谢谢。我知道线程爆炸,我还没有看到它,但我还没有真正做任何事情来控制它。这个小问题只是一个学习辅助工具,很快就会被放弃,所以我不太担心它,但感谢您提供的提示。关于线程爆炸的另一个问题是:检查有多少线程可用,并且只有在线程池中有一些空闲线程时才发布新线程,作为避免线程爆炸的一种方法,这是常见的做法吗?我没有看到任何属性或调用返回a)我创建的仍在运行的线程数或b)剩余的可用线程数。GCD不提供API来检查可用线程或正在使用的线程、可用内核等。我怀疑从理论上讲,人们可能会使用较低级别的API,但这几乎是前所未闻的。通常,我们只使用
concurrentPerform
,它会根据可用的内核数量自动进行优化(这对于计算密集型并行算法非常有用)。或者有时我们使用操作队列
maxConcurrentOperationCount
或非零信号量模式来使用一些合理/任意的数字来避免线程爆炸。我们只是避开了64个工作线程的限制。这与当前的问题无关,但在任何给定的时间,有多少并发调用可能发生?工作线程的数量非常有限,这段代码看起来很可疑,它可能很容易导致线程爆炸,耗尽这些工作线程(在这一点上,您可能会有各种意外行为)。我们通常使用
concurrentPerform
来优化线程的利用率,尽管还有其他解决方案。但是要避免无限制的并发。我不知道你是如何保存结果的,但是要确保同步该操作(使用锁或它自己的同步队列)。如果您还没有完成,您可能需要运行此过程。谢谢。我知道线程爆炸,我还没有看到它,但我还没有真正做任何事情来控制它。这个小问题只是一个学习辅助工具,很快就会被放弃,所以我不太担心它,但感谢您提供的提示。关于线程爆炸的另一个问题是:检查有多少线程可用,并且只有在线程池中有一些空闲线程时才发布新线程,作为避免线程爆炸的一种方法,这是常见的做法吗?我没有看到任何属性或调用返回a)我创建的仍在运行的线程数或b)剩余的可用线程数。GCD不提供API来检查可用线程或正在使用的线程、可用内核等。我怀疑从理论上讲,人们可能会使用较低级别的API,但这几乎是前所未闻的。通常,我们只使用
concurrentPerform
,它会根据可用的内核数量自动进行优化(这对于计算密集型并行算法非常有用)。或者有时我们使用操作队列
maxConcurrentOperationCount
或非零信号量模式来使用一些合理/任意的数字来避免线程爆炸。我们只是避开了64个工作线程的限制。谢谢!我不熟悉