前言:
对于除了主线程外的子线程来说,只有两种方法可以明确一个线程活动,传递一个回调函数给构造函数(直接传入要运行的方法),或者在子类中覆盖run方法。换句话说在Thread的子类中,只有run()和__init__()方法可以覆盖 。
背景
一般情况下针对不断循环调用的函数结构代码。
- 背景一
当我们不断的调用某个函数来执行某个动作时,可能由于调用的频繁导致上一次的调用还没有处理完,下一次的又调用了。这时,我们应该在调用这个函数的循环结构中,将调用函数的代码,采用的 方法一 为:换成调用Thread的代码,然后将要调用的函数传给Thread的target可选参数。方法二 为:重新继承Thread这个类,覆盖run方法,将要调用的代码移入Thread的run方法中。 - 背景二
在一个主线程里,我们也可以将执行不同功能的函数都放入Thread线程中,让线程来启动执行这些动作。或者将不同的函数都重新继承一个线程,然后将函数的代码写入run方法中。
主线程
当一个进程启动之后,会默认产生一个主线程。main()函数启动一个进程进而产生一个主线程。
子线程
通过Threading模块的Thread()类新生成的示例,传入一个要运行的方法,或者覆盖改写子类中的run()方法来生成新线程。
主线程,子线程的关系
- 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束,例子见下面一。
- 当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止,例子见下面二。
- 当我们使用join()时,join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,主线程一直等待全部的子线程结束之后,主线程自身才结束,程序退出。
[t.join() for t in threads ]
socket.accept() & recv()方法
- socket.accept( )阻塞线程的方法,如果没有accept,就一直阻塞线程。
- socket.recv( )阻塞线程的方法,如果没有收到消息就一直阻塞线程
socket的Server端和Client端交流(send &recv)
- 服务端必须生成多个ClientTheread来应对不同的客户端建立的连接,因为
(conn,(ip,port)) = tcpServer.accept()
,即一个客户端的连接,socket.accept()就返回一个 (conn,(ip,port)) ,data = conn.recv(1024)
用来接受客户端发送过来的消息data.decode("utf-8")
来解码,conn.send(text.encode("utf-8"))
用来向客户端编码并发送消息。 - 一个客户端只用生成一个socket对象A,然后A.connect()之后就可以
A.recv(1024)
来接收服务器发送过来的数据,通过tcpClientA.send(text.encode("utf-8"))
来向服务端发送编码好的消息。
线程生成方法
有两种方法来生成一个新的线程活动。第一种:通过要运行的回调对象传入Thread的构造函数。第二种:通过类的继承继承Thread类。然后覆盖Thread的run方法,将要执行的动作写入run方法中。而且只能覆盖run方法。最后调用方法start()来启动线程的状态。
- 通过将要运行的代码编写为一个函数,然后将函数传入线程的初始化(即构造函数)表达式中
- 实例一个线程对象,然后调用start方法,start方法会激活run方法进而执行run方法里的任务或行为。
newthread = ClientThread(ip,port,window)
newthread.start()
Thread.join()方法
join方法是用来确定线程是何时结束的。也就是将子线程与主线程绑定某种关系。主线程必须等待所有的join的子线程结束之后,才能结束。 join就是一个容器,如果里面的子线程都不结束,主线程是没有办法结束的。
初始状态:因为在同一个主进程中,如果有a,b进程start,那么它们开始的顺序是不按照代码的顺序执行的,这个是随机的。主线程开始,主线程结束,a,b随机先跑,随机先死。
- 在线程a加入join之,就会等待a结束之后,才能将b进程加入,相当于给上面的随机现象排个队。执行顺序:主线程,a开始,a结束,主线程结束,b开始,b结束。
- a,b不知道谁先开始,a先死,主线程终止,b继续跑,跑完死;如果是b先死,那么a继续跑,跑完a死,主线程死。b没有join,所以和主线程无关。
- 主线程开始,a开始,a结束,b开始,b结束,主线程结束
Thread对象
Once a thread object is created, its activity must be started by calling the thread’s start() method. This invokes the run() method in a separate thread of control.
- 主线程。
- 通过主线程来创造其他的子线程。
- 线程n。
- 线程没有terminate()函数(与进程的区别)。