现在人们使用一种叫做多线程的并发编程办法, 它能够让程序一口气同时去搞好好几个不同的任务。在这个方面, 大家可以使用标准库里面提供的那些模块来把多线程技术给实现出来。咱们下面就要来详细讲讲具体该怎么去创建线程并且还要管理好这些线程的使用工作情况。
创建线程
在中, 创建线程可以通过创建对象来实现。那个对象里面包含一个参数, 这个参数用来指定线程要去执行的函数。比如说:
在这么一种情形之下, 我们搞出来一个叫做某某名字的函数, 然后把这玩意儿当做一个参数的样子, 塞进了某个对象里面去用着用着, 再接着往下操作, 我们就把那个启动线程的start()这样的方法给调动起来了, 等这个线程真的一脚踢开大门跑起来以后, 它自个儿就会跑去把那函数拿来用一下, 用来干那些个被指派下来的活计。
传递参数
有时候我们需要在线程中传递参数, 可以通过在对象的args参数中传递参数, 例如:
在这个案例里面, 我们把start跟end这两个参数传给了那个函数, 把这些参数弄成一个元组的形式来传递给args这个参数, 让args的值等于括号110这样子, 然后在函数体里我们拿这些参数来做打印数字的那件事。
线程同步
在做多线程编程的时候, 各个线程有可能会去访问那些共享的资源内容, 要是没有弄好相应的同步手段的话, 就有可能出现像是竞态条件还有死锁之类的麻烦问题, 系统里面是提供了多种多样的同步机制给大家使用的, 比如像是有锁也就是我们常说的 Lock、信号量以及条件变量这些东西都是其中的一部分案例, 现在就主要来拿锁这个办法作为例子讲一讲, 看看是怎么在代码编写过程中利用锁这个东西来达到让线程实现同步操作的目的要求的。
在这个具体的例子当中, 我们分别定义了两个不同的函数, 这两个函数各自的作用是用来对全局变量x执行加一的操作或者是减一的操作的, 为了能够对这种竞态条件进行有效的避免, 我们是利用Lock这个对象来实现对x所进行的访问的控制的, 然后在这些已经定义好的函数内部, 我们是调用了相关的中的方法来进行锁的获取操作的, 接下来是进行相应的一些操作处理的, 最后一步则是调用方法来实现了对锁的释放的, 通过这样的方式, 每一个参与运算的线程在进行对变量x的直接访问之前, 首先都必须得到一把锁, 正是因为有了这样一个先后顺序的限制, 所以才从根本上避免了可能发生的竞态条件问题的。
在此处展示的实例里面, 咱们弄出来了两个线程对象, 让它们去跑那些特定的函数代码块。借助于调用起始方法的方式, 把这两个线程给激活起来让其运行, 接着再运用等待方法来确保前面的活儿全都干完了才进行下一步。
最终阶段,我们去查看那个变量x的具体数值是多少, 以此来验证前后几个步骤之间的协调配合是不是真像预想的那样顺利无误。
线程池
在中, 你可以使用类来创建线程池, 以便你同时执行多个任务。它会自动帮助你管理线程的数量和线性的生命周期, 从而可以避免因为创建了太多的线程而导致的系统负载过高的问题出现。
下面呈现的是一个比较基础的例子。
在这个样子里面呢, 我们把这个最大数量的活跃线程的数量设定为了2的这个任务队列给弄好了。接着就是去调用这个()这个函数功能了, 把这两个活给扔上去干。一个活是要把从1开始一直到5中间的那些数字都显示出来。另外一个活则是去完成那个从6一直到10中间的数值的打印操作罢了。
那个方法会返回一个对象, 这个对象是用来表示任务的执行状态以及结果的, 不过在这个例子当中呢, 我们根本没有采用这种对象来把任务的结果给获取到, 而是选择了一种更直接的方式, 也就是直接把那个数字给打印出来。
对象的作用
这个对象是被放置在标准库中的那些模块里面的。它是用来提供的一种异步编程工具。它的主要作用是表示一个还没有做完的异步操作的状态以及结果。
当一个任务被提交到线程池或者进程池中之后, 系统会立即返回一个对象, 这个对象是可以用来查询任务的状态和结果的, 该对象拥有的状态有以下几种:
当那个具体任务全部完成之后, 相关的目标对象本身就会把最终得到的结果给保留保存起来, 用户可以直接通过调用括号里面的方法来把这个结果给获取出来, 一旦这个具体的任务在还没有达到完成状态的时候, 如果这时候直接去调用方法会导致当前运行的线程被卡住进入阻塞状态, 系统必须一直等待直到整个任务彻底结束并且给出对应的返回结果或者抛出异常信息。
除了()方法之外, 对象还提供了其他一些不同的方法。例如, ()方法能够被用来取消掉任务的执行。done()这个方法的用途是去检查任务究竟是不是已经完成了。()这种方法则可以被用来注册回调函数, 这样做的结果是, 在任务结束的那一刻, 它会自动地进行调用。
综合演示例子
下面是具体的一综合案例, 这个用来表明怎么运用对应模块里面的方法和类这样的对象工具, 把图片给同时下载下来并且完成相关操作。
通过使用那个东西, 并且使用另一个东西, 我们能够在一个时间点上下载好几张图像, 这样的话下载的速度就变快了。还有, 运用这个结构可以让我们在处理每一个任务完成之后的结果方面感到很方便, 这样就能达成更加具有弹性的异步程序设计风格。
总结
这篇文本主要讲述了怎么利用某个模块来把线程建立并且管理起来, 这其中涵盖了给线程传递参数、让多个线程同步工作以及使用线程池这些内容。接着文章还提到了在多线程开发里面经常会出现的一些麻烦事, 比如多个地方同时改数据会冲突的情况, 还有两个线程互相等对方导致程序卡死的情况等等。
为了解决这些问题, 文中说明了怎么用锁这个东西把那些错误现象规避掉。所以真正写代码的时候, 得根据具体要解决的问题去挑最合适的同步方式和线程池设置, 这样才能让整个程序跑得更快更稳定。