1多线程概念
2多线程的两种开启方式
3多线程对象的属性或方法
4join与守护线程
5守候线程与守候进程
6GIL与lock
7线程与进程的区别
1多线程概念
在一个进程里开启多个线程,他们共享同一个进程的资源。里面有一个主线程,其余都是其他线程。线程相当于一个车间的流水线,进程相当于一个车间。在进程开启时就会有一个主线程。主线程和新开启的线程共享资源。线程开启的速度很快。
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空间
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
2多线程的两种开启方式:一个是函数一个是类和共享一个内存空间
#方法一 # from threading import Thread # from multiprocessing import Process # import os # def talk(): # print('%s is running' %os.getpid()) # # if __name__ == '__main__': # t=Thread(target=talk) # # t=Process(target=talk) # t.start() # print('主') #方法二 from threading import Thread import os class MyThread(Thread): def __init__(self,name): super().__init__() self.name=name def run(self): print('pid:%s name:[%s]is running' %(os.getpid(),self.name)) if __name__ == '__main__': t=MyThread('egon') t.start() print('主',os.getpid())
和共享一个内存空间
from threading import Thread input_l=[] format_l=[] def talk(): while True: msg=input('>>: ') if not msg:continue input_l.append(msg) def format(): while True: if input_l: res=input_l.pop() format_l.append(res.upper()) def save(): with open('db.txt','a') as f: while True: if format_l: f.write('%s ' %(format_l.pop())) f.flush() if __name__ == '__main__': t1=Thread(target=talk) t2=Thread(target=format) t3=Thread(target=save) t1.start() t2.start() t3.start()
3多线程对象的属性或方法
from threading import Thread,currentThread,activeCount import os,time,threading def talk(): print('%s is running' %currentThread().getName())#打印的是正在运行的线程的名字 # # print(currentThread().getName()) if __name__ == '__main__': # t=Thread(target=talk,name='egon') t=Thread(target=talk)#开线程 t.start()#启动 print(t.name)#打印线程的名字 # print(t.getName())#打印线程的名字 print(t.is_alive())#是否活着 print(currentThread().getName())#打印主线程的名字 print(threading.enumerate())#打印有序列表 # time.sleep(3) # print(t.is_alive())#是否活着 print('主',activeCount())#打印目前存活的进程
4join与守护线程
from threading import Thread,currentThread import time def talk(): time.sleep(2) print('%s is running' %currentThread().getName()) if __name__ == '__main__': t=Thread(target=talk) t.start() t.join()#主线程等着子线程 print('主')
from threading import Thread,currentThread import os,time,threading def talk1(): time.sleep(5) print('%s is running' %currentThread().getName()) def talk2(): time.sleep(10) print('%s is running' %currentThread().getName()) if __name__ == '__main__': t1=Thread(target=talk1) t2=Thread(target=talk2) t1.daemon=True#设置守护线程,主线程挂了它也跟着挂啦 t1.start() t2.start()# print('主线程',os.getpid())
#在这个代码里就会出现t1和t2线程都运行完了, # 对于主线程来说什么时候是结束呢?是除了守护线程外其余的线程都运行完了,主线程就结束,顺带着守候进程离开 from threading import Thread import time def foo(): print(123) time.sleep(5) print("end123") def bar(): print(456) time.sleep(10) print("end456") if __name__ == '__main__': t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon=True t1.start() t2.start() print("main-------")
5守候线程与守候进程
#不管是守护线程还是守候进程:他俩都是守候主线程和父进程的。在主线程和父进程结束的时候就结束了。 # 主线程的结束标志是:在除了守候线程外其余线程都都结束了,才结束 #父进程结束的标志是:在父进程代码运行完了就结束啦。
6GIL与lock
定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.) ''' 结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势
#GIL是cyphton的解释器的全局锁,用它运行一个文件时,会产生一个进程和多个线程。通过全局锁来控制解释器里的数据安全性,但是他不保证用户文件的安全性。用户数据也需要用Lock这把锁要控制。 #文件类型不一样,锁的类型也不一样。
7线程与进程的区别
- Threads share the address space of the process that created it; processes have their own address space.
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.