iOS多线程简介 - Swift版本 1.多线程开发 -- CGD的简单使用

在我们实际开发中, 有难免会遇到一些问题, 比如我要从网上下载一张图片进行修改, 这里就涉及到线程的问题了, 还有就是我们平常使用的下载工具: 迅雷, QQ旋风之类的, 它们可以进行同时下载, 也可以一个一个的来下载, 在这里我们称之为同步和异步, 顾名思义, 所谓的同步就是所有文件一起下载, 异步就是把需要下载的文件一个个排好队来下载.


1.基本概念

在开始说多线程之前, 我们要知道两样东西, 一个是进程, 一个是线程:

进程: 正在进行中的程序就叫做进程, 负责程序运行的内存分配, 每一个进程都有自己独立的虚拟内存空间.

线程: 线程是进程中一个独立的执行路径(控制单元), 一个进程中至少包含一条线程(主线程), 可以将耗时的操作或者执行放到另一个线程里.

说白了, 进程就是为程序分配内存的, 而线程就是用来控制程序代码的实际运行.

举个例子, 我们的程序运行, 都是按照代码从上往下的执行, 但如果遇到需要下载图片的时候, 它就会卡在这里, 等待图片下载完成才会执行下一步, 这样子就不符合我们的实际体验了, 所以我们会把下载图片放到子线程里去操作, 等到下载完成之后才传回给主线程, 这就是多线程的好处, 既不会影响主线程的运行, 又可以完成下载图片的任务.

提示:
1.dispatch_async 异步操作,会并发执⾏,无法确定任务的执⾏顺序
2.dispatch_sync 同步操作,会依次顺序执⾏,能够决定任务的执行顺序

PS: 线程是有限的, 不可以无休止的增加, 而主线程的大小只有1MB, 子线程都是512KB.


2.GCD队列

串行队列: 队列中的任务只会顺序执⾏

    func gcdDemo1() {
        // 将操作放在队列中
        // 在 C 语言函数中, 定义类型, 绝大多数都是以_t或者ref 结尾
        // 使用串行队列的异步任务, 可以节省资源, 新建线程是需要有资源消耗的, 不能无休止的去新建线程

        // 应用案例:
        // 从网上下载图片
        // 滤镜(高光, 红眼...)
        var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo1", DISPATCH_QUEUE_SERIAL)
        let i = 0

        for i in 0...10 {
            dispatch_async(q, { () -> Void in
                println(NSThread.currentThread())
            })
        }
        // 非 ARC 开发时, 一定要 release
        //    dispatch_release(q);

        // 串行队列的同步任务, 也会在主线程中运行
        // 在实际开发中, 极少人用
        // 面试又可能会用到
        for i in 0...9 {
            // 同步任务, 顺序执行
            dispatch_async(q, { () -> Void in
                println("\(NSThread.currentThread()) - \(i)")
            })
        }
    }

并行队列: 队列中的任务通常会并发执⾏

    func gcdDemo2() {
        // 特点: 没有顺序, 程序员不可控
        // 应用场景: 并发执行的, 没有先后顺序
        // 并行队列容易出错, 并行队列创建的子线程数量同样是不可控
        var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo2", DISPATCH_QUEUE_CONCURRENT)

        for i in 0...9 {
            // 同步任务
            dispatch_sync(q, { () -> Void in
                println("\(NSThread.currentThread()) - \(i)")
            })
            // 异步任务
            dispatch_async(q, { () -> Void in
                // [NSThread currentThread] 可以在开发中跟踪当前的线程.
                // number = 1表示主线程
                // number = 2或者其他, 表示子线程, 这里是2, 所以是第2个子线程
                println("\(NSThread.currentThread()) - \(i)")
            })
        }
    }

全局队列

    func gcdDemo3() {
        // 全局队列与并行队列的区别
        // 1< 不需要创建, 直接GET就可以使用
        // 2< 两个队列的执行效果相同
        // 3< 全局队列没有名称, 调试时无法确认准确队列
        var q: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
        for i in 0...9 {
            // 异步任务
            dispatch_async(q, { () -> Void in
                println("\(NSThread.currentThread()) - \(i)")
            })
            // 同步任务
            dispatch_sync(q, { () -> Void in
                println("\(NSThread.currentThread()) - \(i)")
            })
        }
    }

主线程队列

    func gcdDemo4() {
        var q = dispatch_get_main_queue()
        for i in 0...9 {
            // 异步任务, 并发执行, 保持队形的
            dispatch_async(q, { () -> Void in
                println("\(NSThread.currentThread()) - \(i)")
            }); 
            // 同步任务      
            // 注意, 在主线程队列中不可以使用同步任务, 否则会造成线程阻塞
//            dispatch_sync(q, { () -> Void in
//                println("come here baby!")
//            });
        }
    }

3.GCD总结

串⾏队列
1.同步任务, 不需要新建线程, 异步任务, 需要⼀个⼦线程, 线程的创建和回收不需要程序员参与!
2.“是最安全的一个选择”串⾏行队列只能创建!

并行队列
1.同步任务, 不需要创建线程并行队列, 异步任务, 有多少个任务, 就开N个线程执⾏行 无论什么队列和什么任务, 线程的创建和回收不需要程序员参与.

2.线程的创建回收⼯作是由队列负责的 “并发”编程, 为了让程序员从负责的线程控制中解脱出来! 只需要⾯对队列和任务!

GCD的好处
1.通过GCD, 开发者不⽤再直接跟线程打交道, 只需要向队列中添加代码块即可.

2.GCD在后端管理着⼀个线程池, GCD不仅决定着代码块将在哪个线程被执⾏, 它还根据可用的系统资源对这些线程进⾏管理. 从而让开发者从线程管理的工作中解放出来, 通过集中的管理线程, 缓解大量线程被创建的问题.

3.使⽤用GCD, 开发者可以将工作考虑为一个队列, 而不是一堆线程,这种并行的抽象模型更容易掌握和使⽤.

GCD的队列
1.GCD公开有5个不同的队列: 运⾏在主线程中的主队列, 3个不同优先级的后台队列, 以及一个优先级更低的后台队列(⽤于 I/O).

2.⾃定义队列: 串⾏行和并⾏行队列, ⾃定义队列⾮常强大,建议在开发中使⽤, 在⾃定义队列中被调度的所有Block最终都将被放⼊到系统的全局队列中和线程池中.

提示: 不建议使⽤用不同优先级的队列, 因为如果设计不当, 可能会出现优先级反转, 即低优先级的操作阻塞⾼优先级的操作.


好了, 这次我们就讲到这里, 下次我们继续~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 nmos 晶体管 Verilog-A 建模代码的示例: ``` `include "constants.vams" module nmos_v1 (drain, gate, source, body, vbs, vgs, vds, ids); // 定义端口 inout drain, source, gate, body; input vbs, vgs, vds; output ids; // 定义参数 parameter REAL W = 1e-6; // 晶体管宽度 parameter REAL L = 1e-6; // 晶体管长度 parameter REAL tox = 2.5e-9; // 氧化层厚度 parameter REAL nsub = 1e16; // 衬底掺杂浓度 parameter REAL eps_ox = 3.9*8.854e-12; // 氧化层介电常数 parameter REAL eps_si = 11.7*8.854e-12; // 硅介电常数 parameter REAL mu = 0.05; // 迁移率 // 定义局部变量 real Vth; real vdsat; real idsat; real vfb; real phi_f; real eps_eff; real Cox; real Cgs; real Cgd; real Cgb; real Cdb; real gamma; real lambda; real W_eff; real L_eff; real Vgs; real Vds; real Vbs; real VT; real VG; real VD; real VSB; real ID; real Rd; real Rs; real gm; real gmb; real go; real Cgso; real Cgdo; real Cgbo; real Cdbo; real Cgsd; real Cgbd; real Cox_inv; real VDD; // 计算局部变量 Vth = 0.5 * (sqrt(4*nsub*eps_si*phi_f) + gamma*sqrt(eps_si)*Vsb - Vdsat); vdsat = Vgs - Vth; idsat = 0.5*mu*Cox*W_eff/L_eff*(Vgs-Vth)^2*(1+lambda*Vds); vfb = -phi_f + eps_si/eps_ox*phi_f; phi_f = kT/q*log(nsub/ni); eps_eff = eps_si*eps_ox/(eps_si+eps_ox); Cox = eps_ox/tox; Cgs = Cox*W*L_eff/(L_eff+W_eff); Cgd = Cgs; Cgb = Cox*W*Leff/(Leff+W_eff); Cdb = Cox*Leff*L/(L+W_eff); gamma = sqrt(2*q*eps_si*nsub)/(Cox*Vt); lambda = 0; W_eff = W-gamma*(sqrt(phi_f-Vbs)-sqrt(phi_f)); L_eff = L-lambda*W_eff; VT = Vt*log((nsub)/ni); VG = gate; VD = drain; VSB = body; ID = 0; Rd = 0; Rs = 0; gm = 0; gmb = 0; go = 0; Cgso = 0; Cgdo = 0; Cgbo = 0; Cdbo = 0; Cgsd = 0; Cgbd = 0; Cox_inv = 1/Cox; VDD = 1.8; // 计算电流 if(VD > VG) begin ID = mu*Cox*W_eff/L_eff*(Vgs-Vth-Vds/2)*Vds*(1+lambda*Vds); Rd = 1/lambda/mu/W_eff*Cox*L_eff; end else begin ID = mu*Cox*W_eff/L_eff*(Vgs-Vth)^2*(1+lambda*Vds); Rd = 0; end if (VG <= Vth) begin ID = 0; Rd = 0; end if (ID > idsat) begin ID = idsat; Rd = Vdsat/idsat; end if (ID < 0) begin ID = 0; Rd = Vdsat/idsat; end // 计算导通电阻 if (VDS <= Vgs-Vth) begin Rs = 1/(mu*Cox*W_eff/L_eff*(Vgs-Vth-VDS/2)); end else begin Rs = 1/(2*mu*Cox*W_eff/L_eff*(Vgs-Vth)*(Vdsat-VDS/2)); end // 计算导通电阻的变化量 if (VDS < Vgs-Vth) begin gm = mu*Cox*W_eff/L_eff*(2*(Vgs-Vth-VDS/2)); gmb = 0; go = mu*Cox*W_eff/L_eff*Vdsat; Cgso = Cox*W_eff*gamma/2; Cgdo = Cox*W_eff*gamma/2; Cgbo = Cox*Leff/gamma; Cdbo = Cox*Leff/gamma; Cgsd = Cox*L_eff/gamma; Cgbd = 0; end else if (VDS < vdsat) begin gm = mu*Cox*W_eff/L_eff*(2*(Vgs-Vth-Vdsat/2)); gmb = 0; go = mu*Cox*W_eff/L_eff*Vdsat; Cgso = Cox*W_eff*gamma/2; Cgdo = Cox*W_eff*gamma/2; Cgbo = Cox*Leff/gamma; Cdbo = Cox*Leff/gamma; Cgsd = Cox*L_eff/gamma; Cgbd = 0; end else begin gm = mu*Cox*W_eff/L_eff*(2*(Vgs-Vth-Vdsat/2)); gmb = 0; go = 0; Cgso = Cox*W_eff*gamma/2; Cgdo = Cox*W_eff*gamma/2; Cgbo = Cox*Leff/gamma; Cdbo = Cox*Leff/gamma; Cgsd = Cox*L_eff/gamma; Cgbd = 0; end // 输出电流和阻值 ids = ID; endmodule ``` 该代码定义了一个名为 `nmos_v1` 的模块,其中包含了各种局部变量和计算公式,以及从输入端口 `drain`, `gate`, `source`, `body`, `vbs`, `vgs`, `vds` 中读取输入信号的代码。最后,该模块通过输出端口 `ids` 输出计算出的电流值。在模拟器中调用该模块时,需要传递相关参数,如晶体管的宽度、长度、氧化层厚度、衬底掺杂浓度等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值