07 线程 与进程类似

 

一、什么是线程

在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程

进程只是用来把资源集中到一起,提供代码运行所需要的资源(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位

  线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程

  车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线

  流水线的工作需要电源,电源就相当于cpu

 

多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间

  相当于一个车间内有多条流水线,都共用一个车间的资源。

      例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。

 

若多个线程都是cpu密集型的,那么并不能获得性能上的增强(一直计算都不带停的那种)

但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。

二、线程创建开销小

1.创建进程的开销要远大于线程?

  如果我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即cpu(单核cpu)

  一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程)

  创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)

  而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小

 

2.进程之间是竞争关系,线程之间是协作关系?

  不同的进程直接是竞争关系,是不同的程序员写的程序运行的

  车间直接是竞争/抢电源的关系,迅雷抢占其他进程的网速,360把其他进程当做病毒干死


  同一个进程的线程之间是合作关系,是同一个程序写的程序内开启动

  一个车间的不同流水线式协同工作的关系,迅雷内的线程是合作关系,不会自己干自己

三、进程线程不同之处

地址空间 :线程共享创建它的进程的地址空间;进程有自己的地址空间。

数据使用:线程可以直接访问其进程的数据段,共享;进程有自己的父进程数据段副本,相互间数据不共享。

通信方式:线程可以直接与其进程的其他线程通信;进程必须使用进程间通信与兄弟进程通信。

创建方式:新线程很容易创建;新进程需要父进程的重复。

控制能力:线程可以对同一进程的线程进行相当大的控制;进程只能对子进程进行控制。

主更改对子影响:对主线程的更改(取消、优先级更改等)可能会影响进程的其他线程的行为;对父进程的更改不会影响子进程。

四、创建线程的两种方式

multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性

#第一种 直接创建

from threading import Thread
import time

def task(name):
    print('%s is running'%name)
    time.sleep(3)
    print('%s is over'%name)
# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
t = Thread(target=task,args=('egon',))
t.start()  # 告诉操作系统开辟一个线程  线程的开销远远小于进程,会立刻创建立刻输出
print('')
'''
egon is running  #线程运行贼快,不是先输出 '主'
主
egon is over
'''

#第二种  创建类方法

from threading import Thread
import time

class MyThread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running'%self.name)
        time.sleep(3)
        print('%s is over'%self.name)

t = MyThread('egon')
t.start()
print('')
'''
egon is running  #线程运行贼快,不是先输出 '主'
主
egon is over
'''

五、线程对象及其他方法

#os.getpid()    主线程和子线程线程号一毛一样
#t.join() 主线程等待子线程运行结束
#active_count() 当前活跃线程数
#current_thread().name 当前线程名

from threading import Thread,current_thread,active_count
import time
import os

def task(name,i):
    print('%s is running'%name)
    # print('子current_thread:',current_thread().name)  #子current_thread: Thread-1
    # print('子',os.getpid())  #子 7120  这里和主线程进程号一毛一样
    time.sleep(i)

    print('%s is over'%name)

t = Thread(target=task,args=('egon',1))
t1 = Thread(target=task,args=('jason',2))
t.start()  
t1.start()
t1.join()  # 主线程等待子线程运行完毕
print('当前正在活跃的线程数',active_count())
print('')
# print('主current_thread:',current_thread().name)  #主current_thread: MainThread
# print('主',os.getpid())  #主 7120

'''
egon is running
jason is running
egon is over
jason is over
当前正在活跃的线程数 1
主
'''

 

六、守护线程

为什么主线程运行结束之后需要等待子线程结束才能结束呢?

主线程的结束也就意味着进程的结束
主线程必须等待其他非守护线程的结束才能结束(不用管守护线程的死活)
(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了进程就结束了,资源也就销毁了)
from threading import Thread,current_thread
import time

def task(i):
    print(current_thread().name)
    time.sleep(i)
    print('GG')

t = Thread(target=task,args=(1,))
t.daemon = True
t.start()
print('')

 

from threading import Thread
from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True
    t1.start()
    t2.start()
    print("main-------")
'''
123
456
main-------  #主线程虽然运行完了,但是一定会等到t2结束自己才会死
end123       #主线程并没有死,自己当然也不会死
end456
'''
线程死亡时机

 

七、线程间通信

共享资源,直接通信

from threading import Thread

money = 666

def task():
    global money
    money = 999

t = Thread(target=task)
t.start()
t.join()
print(money)  #999  直接就通信了
 

八、线程互斥锁

from threading import Thread,Lock
import time

n = 100

def task(mutex):
    global  n
    mutex.acquire()
    tmp = n
    time.sleep(0.1)
    n = tmp - 1
    mutex.release()

t_list = []
mutex = Lock()
for i in range(100):
    t = Thread(target=task,args=(mutex,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()  #让主线程等着每一个线程运行完毕再输出n
print(n)  #0

 

 



 

posted @ 2019-08-12 20:23  www.pu  Views(219)  Comments(0Edit  收藏  举报