所以我正在练习线程,但我有一个要求。 我想等待第一个api调用完成,然后执行第二个api(就像等待异步),如果第一个未完成,我想在那里停止代码,直到完成。
所以,我写了这个。告诉我是否正确,或者是否有更好的方法
func myFunction() {
var a: Int?
let group = DispatchGroup()
group.enter()
DispatchQueue.global().asyncAfter(deadline: .now() + 4) {
a = 1
print("First")
group.leave()
}
group.wait()
group.enter()
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
a = 3
print("Second")
group.leave()
}
// wait ...
group.wait()
group.notify(queue: .main) {
print(a) // y
}
}
答案 0 :(得分:0)
别等。
在第一个的完成处理程序中运行第二个API调用
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: { index: path.resolve(__dirname, "static_src", "index.js") },
output: {
path: path.resolve(__dirname, "static_compiled"),
publicPath: "/static/", // Should match Django STATIC_URL
filename: "[name].js", // No filename hashing, Django takes care of this
chunkFilename: "[id]-[chunkhash].js", // DO have Webpack hash chunk filename, see below
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
],
module: {
rules: [
{
test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}, // to transform JSX into JS
{
test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"]},
{
test: /\.css$/, use: ["style-loader", "css-loader"]},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader'},
{
test: /\.svg$/,
loader: 'svg-inline-loader'},
/* {
test: /\.(ico|png|jpg|gif)$/,
loader: 'file-loader'} */
{
test: /\.(ico|png|svg|jpg|gif|jpe?g)$/,
use: [
{
options: {
name: "[name].[ext]",
outputPath: "img/"
},
loader: "file-loader"
}
]
}
],
},
resolve: {
alias: {
shared: path.resolve(__dirname, 'node_modules', 'bower_components')
},
extensions: ['.js', '.ts', 'jsx', 'tsx']
},
devServer: {
writeToDisk: true, // Write files to disk in dev mode, so Django can serve the assets
}
}
答案 1 :(得分:0)
就像等待异步
对于Swift来说,缺乏内置的语言级别await async
机制是一个严重的问题,并且可能会在以后的版本中得到解决。同时,Swift基本上没有内置的语言级线程执行机制。您必须通过与Cocoa / Objective-C(大型中央调度,NSOperation)或其他处理异步性的框架(Combine)进行对话来手动处理。
您关注的特定问题是我所说的
最简单的方法是,如您所知,在第一个异步调用的执行处理程序的末尾执行第二个异步调用。显然,这对于安排许多任务不是很普遍。
您当然可以按照概述的方式使用DispatchGroup。您对模式的陈述几乎是正确的。您不需要最后一个wait
,而且更重要的是,您必须从头开始进入后台队列,因为在主队列上使用DispatchGroup是非法的。就目前而言,您的代码可以有效地阻止我们等待的主队列,这是您绝对不能做的事情。
您可以创建一个串行OperationQueue并将Operation对象加载到其上。这是一个更为通用的机制。您可以使Operation对象彼此依赖。在Combine框架问世之前,这是最佳的通用解决方案。
如果您可以将自己限制在iOS 13及更高版本中,则Combine框架是最常规的异步序列化方法。有关进一步的讨论,请参见Combine framework serialize async operations。
答案 2 :(得分:0)
Swift 5.5 和 Xcode 13.0 带来了 async/await,因此您可以执行以下操作:
import Foundation
print("Hello, World!")
// Returns a 1 after a 3-second delay
func giveMeAOne() async -> Int {
Thread.sleep(forTimeInterval: 3.0)
return 1
}
// Returns a 5 after a 3-second delay
func giveMeAFive() async -> Int {
Thread.sleep(forTimeInterval: 3.0)
return 5
}
func myFunction() async {
var a: Int = 0
print(a)
a += await giveMeAOne()
print(a)
a += await giveMeAFive()
print(a)
}
async {
await myFunction()
}
sleep(7) // added at the end so that process doesn't exit right away
请注意,上述内容是在 Xcode 中作为 macOS 命令行工具构建的,而不是使用 Swift Playgrounds。从 Xcode 13.0 beta 1 开始,不幸的是,Swift Playgrounds 在很多的异步/等待内容上失败了。
上面的代码按顺序运行它们,并对 myFunction 进行了相当多的清理。但是请注意,这不会引入任何并发。 giveMeAOne() 和 giveMeAFive() 都按顺序运行。
如果您想同时运行 4 个函数调用,您可以这样做:
/// Returns a random integer from 1 through 10, after a 6-second delay
func randomSmallInt() async -> Int {
Thread.sleep(forTimeInterval: 6)
return Int.random(in: 1 ... 10)
}
/// Fetches 4 random integers, summing them
func myFunction() async {
// print timestamp
print(Date())
async let a = randomSmallInt()
async let b = randomSmallInt()
async let c = randomSmallInt()
async let d = randomSmallInt()
// This awaits for a, b, c, and d to all complete.
// You can only await a value once.
let numbersToAdd = await [a, b, c, d]
var sum = 0
for number in numbersToAdd {
print("adding \(number)")
sum += number
}
print("Sum = \(sum)")
// print another timestamp, so you can see that the async let statements ran
// concurrently, rather than sequentially
print(Date())
}
async {
await myFunction()
}
// make sure we have time to finish before process exits
Thread.sleep(forTimeInterval: 10)
当你运行这个时,你可以从时间戳看到总执行时间只花了大约 6 秒——因为所有的 async let ...
语句都是并发执行的。
如果您有固定数量的需要异步调用的东西,这很有效。但是,如果您想进行 100 次异步函数调用,比如加载图像或其他东西,该怎么办?
你可能认为你可以做这样的事情,这会奏效,但会同步运行所有东西——可能不是你想要的:
// Don't do this -- these all run sequentially
var sum = 0
for _ in 0 ..< 100 {
async let value = randomSmallishInt()
let number = await value
print("Adding \(number)")
sum += number
}
如果您想做任意或未知数量的异步事情,最好使用taskGroup
。为了使事情更清晰,这段代码比它需要的要冗长一些。 注意:Xcode 13.0 beta 在 print
语句输出方面存在问题,缺少大部分。无论如何,这里是:
/// Returns a random integer from 1 through 10
func randomSmallInt() async -> Int {
Thread.sleep(forTimeInterval: 6)
return Int.random(in: 1 ... 10)
}
func myFunction_arbitrary_repetitions_asynchronously() async {
// print timestamp
print(Date())
// This is pretty cool --
// `withTaskGroup` creates a context for executing a group of async tasks
// In this case, `Int.self` specifies that each individual task will return
// an Int. `[Int].self` specifies that the entire group will return an array of Ints:
let numbers = await withTaskGroup(of: Int.self, returning: [Int].self) { group in
// Repeat 100 times
for _ in 0 ..< 100 {
// Run the next thing asynchronously
group.async {
return await randomSmallInt()
}
}
// Iterate through results
var result: [Int] = []
for await individualResult in group {
result.append(individualResult)
}
return result
}
var sum = 0
for number in numbers {
print("Adding \(number)")
sum += number
}
print("Sum = \(sum)")
// print another timestamp, so you can see that the async let statements ran
// concurrently, rather than sequentially
print(Date())
}
async { await myFunction_arbitrary_repetitions_asynchronously() }
Thread.sleep(10)
你可以大大缩短这个时间:
func myFunction_arbitrary_repetitions_asynchronously_short() async {
// print timestamp
print(Date())
// In this case, the taskGroup just returns the sum
let sum = await withTaskGroup(of: Int.self, returning: Int.self) { group in
// Repeat 100 times
for _ in 0 ..< 100 {
// Run the next thing asynchronously
group.async {
return await randomSmallInt()
}
}
// Iterate through results
var sum = 0
for await individualResult in group {
print("Adding \(individualResult)")
sum += individualResult
}
return sum
}
print("Sum = \(sum)")
// print another timestamp, so you can see that the async let statements ran
// concurrently, rather than sequentially
print(Date())
}
async { await myFunction_arbitrary_repetitions_asynchronously_short() }
重要提示:Xcode 13.0 beta 1 在处理此代码时变得很不稳定。具体来说,调试器喜欢在进程尚未完成时分离。例如,许多 print
语句的输出不会出现,并且在异步代码中使用断点很困难。构建命令行工具,然后运行生成的可执行文件(在 ~/Library/Developer/Xcode/DerivedData//Build/Products/Debug 中找到)至少会显示打印语句的所有输出.