前言:
对于除了主线程外的子线程来说,只有两种方法可以明确一个线程活动,传递一个回调函数给构造函数(直接传入要运行的方法),或者在子类中覆盖run方法。换句话说在Thread的子类中,只有run()和__init__()方法可以覆盖 。
主线程
当一个进程启动之后,会默认产生一个主线程。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"))
来向服务端发送编码好的消息。
线程生成方法
- 通过将要运行的代码编写为一个函数,然后将函数传入线程的初始化(即构造函数)表达式中
- 实例一个线程对象,然后调用start方法,start方法会激活run方法进而执行run方法里的任务或行为。
newthread = ClientThread(ip,port,window)
newthread.start()
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()函数(与进程的区别)。