进程与线程的区别:
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:是进程的一个执行单元,任务调度和执行的基本单位。
区别:
- 在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
- 所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行。(通过CPU调度,在每个时间片中只有一个线程执行)
- 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。
- 包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
P y t h o n Python Python中的多线程:
python中多线程的使用有两种方式:
- 函数
- 类包装线程对象
1.函数:
调用threading模块中的
threading.Thread函数来产生新线程。
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
参数:
-
g
r
o
u
p
group
group
线程组,默认为None,为以后拓展ThreadGroup类实现而保留。 -
t
a
r
g
e
t
target
target
用于run()方法调用的可调用对象。默认是None,表示不需要调用任何方法。 -
n
a
m
e
name
name
线程名称,默认情况下由"Thread-N"构成,其中N为十进制数 -
a
r
g
s
args
args
调用目标函数的参数元组 -
k
w
a
r
g
s
kwargs
kwargs
调用目标函数的关键字参数字典
def fun():
...
t1 = threading.Thread(target=fun,name="t1")
t1.start()
2.继承threading.Thread来自定义线程类,本质是重构Thread类中的run方法。(推荐)
class MyThread(threading.Thread):
def __init__(self,n):
super(MyThread,self).__init__()
self.n=n
def fun(self):
...
t1 = MyThread("t1")
t1.start()
t r e a d i n g . T h r e a d treading.Thread treading.Thread对象的一些常用方法:
-
r
u
n
(
)
run()
run()
用以表示线程活动的方法 -
s
t
a
r
t
(
)
start()
start()
启动线程活动 -
j
o
i
n
(
[
t
i
m
e
]
)
join([time])
join([time])
等待至线程中止。例如主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后,才可以接着往下执行,那么在调用这个线程时可以使用被调用线程的join方法。join([timeout]) 里面的参数时可选的,代表线程运行的最大时间,即如果超过这个时间,不管这个此线程有没有执行完毕都会被回收,然后主线程或函数都会接着执行的,如果线程执行时间小于参数表示的时间,则接着执行,不用一定要等待到参数表示的时间。 -
i
s
A
l
i
v
e
(
)
isAlive()
isAlive()
返回线程是否活动 -
g
e
t
N
a
m
e
(
)
getName()
getName()
返回线程名 -
s
e
t
N
a
m
e
(
)
setName()
setName()
设置线程名 -
s
e
t
D
e
a
m
o
n
(
)
setDeamon()
setDeamon()
主线程A中,创建了子线程B,并且在主线程A中调用了B.setDaemon(True),这个的意思是,把主线程A设置为守护线程,这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出。这就是setDaemon方法的含义,这基本和join是相反的。此外,还有个要特别注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起,只有等待了所有线程结束它才结束。
threading类的重要函数:
-
a
c
t
i
v
e
c
o
u
n
t
(
)
active_count()
activecount()
返回当前存活的线程类 Thread 对象。 -
c
u
r
r
e
n
t
t
h
r
e
a
d
(
)
current_thread()
currentthread()
返回当前对应调用者的控制线程的 Thread 对象。 -
g
e
t
i
d
e
n
t
(
)
get_ident()
getident()
返回当前线程的 “线程标识符”。它是一个非零的整数。 -
e
n
u
m
e
r
a
t
e
(
)
enumerate()
enumerate()
以列表形式返回当前所有存活的 Thread 对象。 -
m
a
i
n
t
h
r
e
a
d
(
)
main_thread()
mainthread()
返回主 Thread 对象。一般情况下,主线程是Python解释器开始时创建的线程。 -
s
t
a
c
k
s
i
z
e
(
[
s
i
z
e
]
)
stack_size([size])
stacksize([size])
返回创建线程时用的堆栈大小。
1.原始锁(互斥锁)
t
h
r
e
a
d
i
n
g
.
L
o
c
k
threading.Lock
threading.Lock
实现原始锁对象的类。一旦一个线程获得一个锁,会阻塞随后尝试获得此锁的线程,直到它被释放;但任何线程都可以释放它。
lock=threading.Lock() #锁对象
lock.acquire() #关锁
lock.release() #开锁
# acquire和release一般写在run函数里,例如:
# lock.acquire()
# change something...
# lock.release()
2.递归锁(RLock)
互斥锁锁住之后,不管是此线程还是其他线程都不可以再用此锁,而递归锁锁住之后,此进程还可以继续acquire,但其他进程不可以。即此锁支持同一线程中多次请求同一资源。需要注意的是,acquire和release必须成对出现。
缺点:锁住的代码只能以单线程执行;由于可以存在多个锁,不同的线程可以持有不同的锁,试图获得对方持有的锁时,可能会造成死锁。
3.高级锁(threading.Condition())
可以使一个或多个进程等待知道其他线程调度或通知。
wait
该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用 wait()之前,线程必须要获得该对象的对象监视器锁,即只能在同步方法或同步块中调用 wait()方法。调用wait()方法之后,当前线程会释放锁,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock。
notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,
默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,
否则会触发RuntimeError。notify()不会主动释放Lock。
notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少)
lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,
默认创建一个RLock(),一般都用默认。
import threading,time
from random import randint
class Producer(threading.Thread):
def run(self):
global L
while True:
val=randint(0,100)
# print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
print('生产者',self.name,' Append'+str(val),L)
if lock_con.acquire():
L.append(val)
lock_con.notify()
lock_con.release()
time.sleep(3)
class Consumer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire()
if len(L)==0:
lock_con.wait()
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
print('消费者',self.name,'Delete'+str(L[0]),L)
del L[0]
lock_con.release()
time.sleep(0.5)
if __name__=='__main__':
L=[]
lock_con=threading.Condition()
threads=[]
for i in range(5):
threads.append(Producer())
threads.append(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()