我想干点什么呢?有点目的性才有做下去的动力!
-
多线程1
据说这是一个最简单的多线程,也是找别人的看的,我真的不会使用帮助文档。据说还有一个thread,但是不推荐使用了,所以直接从threading入门
#coding=utf-8
import threading;
from time import sleep;
def music():
for i in range(15):
print('nusic--->',i);
sleep(2);
def movie():
for i in range(15):
print('movie------->',i);
sleep(3);
if __name__=='__main__':
threads=[];#创建一个线程数组,存放创建的线程
t1=threading.Thread(target=music);#创建第一个线程,如果target的函数有参数,以tuple形式作为第二个参数传入
t2=threading.Thread(target=movie);#创建第二个线程
threads.append(t1);#将创建的线程加入线程数组
threads.append(t2);
for t in threads:
t.setDaemon(True);#setDaemon(True)将线程声明为守护线程,而且必须在star()方法前设置,如果不设置,我也不知道会怎样。。。
t.start();#启动线程
for t in threads:
print(threading.currentThread());
t.join();#如果没有这句,那么启动了线程后,就直接向下执行了,主线程并不会等待子线程结束再继续,而且主线程结束了,子线程也就over了。
#print(threading.currentThread());
print('all done ! ');
join()
的主要作用就是在它非空时阻塞主线程(或者说阻塞子线程的父线程?)。貌似join()
中只能容下一个线程,当把print(threading.currentThread());
放在下面时,只输出一次结果,这是正确的。当放在上面一点时,会在第一个次for循环输出一次,待第一个被join()
的子线程结束时输出第二次,哦,好像就应该这样啊,现在外面是主线程,它阻塞了主线程他肯定要等第一个执行完才会继续,开来猜测完全正确。
-
多线程2
继承自threading.Thread拥有自己的可自定义线程类
.共享数据,线程同步
数据共享。当多个线程都要去修改某一个共享数据的时候,我们需要对数据访问进行同步。
- Rlock,实现同步
#coding=utf-8
import threading;
from time import sleep;
class myThreading(threading.Thread):#继承threading.Thread
num=0;
myLock=threading.RLock();
def __init__(self,name,sleepSec):
threading.Thread.__init__(self);#父类初始化
self.__name=name;
self.__sleepSec=sleepSec;
def run(self):#__init__和run是必须重写的
while(True):
self.__class__.myLock.acquire();#获得锁,成功获得锁定后返回True。我们把修改共享数据的代码成为“临界区”。必须将所有“临界区”都封闭在同一个锁对象的acquire和release之间。
print('%s acquire+ the lock, num= %d'%(self.__name,self.__class__.num));
if(self.__class__.num >= 4):
self.__class__.myLock.release();
print('%s release- the lock for bigger than, num= %d'%(self.__name,self.__class__.num));
break;
self.__class__.num +=1;
print('%s release- the lock, num= %d'%(self.__name,self.__class__.num));
self.__class__.myLock.release();
sleep(self.__sleepSec);
if __name__=='__main__':
t1=myThreading("t1",5);
t2=myThreading("t2",2);
t1.setDaemon(True);
t2.setDaemon(True);
t1.start();
t2.start();
t1.join();
t2.join();
输出
t1 acquire+ the lock, num= 0
t1 release- the lock, num= 1
t2 acquire+ the lock, num= 1
t2 release- the lock, num= 2
t2 acquire+ the lock, num= 2
t2 release- the lock, num= 3
t2 acquire+ the lock, num= 3
t2 release- the lock, num= 4
t1 acquire+ the lock, num= 4
t1 release- the lock for bigger than, num= 4
t2 acquire+ the lock, num= 4
t2 release- the lock for bigger than, num= 4
2.条件同步
所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。 它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。Condition的价值在于其提供的wait和notify的语义
#coding=utf-8
import threading;
num=0;
con=threading.Condition();#条件变量
class Producer(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self);
self.__name=name;
def run(self):
global num;
con.acquire();#取得条件变量
if(num>0):
con.wait();#有足够的产品,就可以停下来等待,也就是释放资源了
else:
for i in range(5):
num +=2;
print('producer>>>>>>%d'%num);
con.notify();#发出消息,我准备好了,释放资源了,可以来用了
print('producer done !');
con.release();#彻底释放了
class Consumer(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self);
def run(self):
global num;
con.acquire();#取得条件变量
if(num==0):
print('consumer waiting......');
con.wait();#没有产品,等待生产,
else:
for i in range(5):
num-=1;
print('consuming......{num}');
con.notify();#发出通知,没货了,快生产
print('consumer done !');
con.release();
if __name__=='__main__':
print('start Consumer');
c=Consumer('consumer');
print('start Producer');
p=Producer('producer');
c.setDaemon(True);
p.setDaemon(True);
c.start();
p.start();
c.join();
p.join();
#抱歉,上面那个不对,这个才可以运行。主要在于上面误读了notify(),它只是发出通知,并没有释放资源的作用,
#所以,notify之后还要release其他线程才能操作共享资源。
#coding=utf-8
import threading;
import time;
class Goods:
def __init__(self):
self.__num=0;
def add(self):
self.__num+=2;
def sub(self):
self.__num-=1;
def get(self):
return self.__num;
def empty(self):
if(self.__num > 0):
return False;
else:
return True;
class Producer(threading.Thread):
def __init__(self,name,con,num):
threading.Thread.__init__(self);
self.__name=name;
self.__con=con;
self.__goods=num;
print('creat Producer\n');
def run(self):
print('start Producer\n');
con=self.__con;
goods=self.__goods;
while(True):
con.acquire();#取得条件变量
if(not goods.empty()):
con.wait();#有足够的产品,就可以停下来等待,也就是释放资源了
else:
goods.add();
print('producer>>>>>>%d'%goods.get());
con.notify();#发出消息,我准备好了,释放资源了,可以来用了
print('producer done !');
con.release();#彻底释放了
time.sleep(2);
class Consumer(threading.Thread):
def __init__(self,name,con,num):
threading.Thread.__init__(self);
self.__name=name;
self.__con=con;
self.__goods=num;
print('create Consumer');
def run(self):
print('start Consumer');
con=self.__con;
goods=self.__goods;
while(True):
con.acquire();#取得条件变量
if(goods.empty()):
print('consumer waiting......');
con.wait();#没有产品,等待生产,
else:
goods.sub();
print('consuming......%d'%goods.get());
con.notify();#发出通知,没货了,快生产
print('consumer done !');
con.release();
time.sleep(5);
if __name__=='__main__':
con=threading.Condition();#条件变量
goods=Goods();
c=Consumer('consumer',con,goods);
p=Producer('producer',con,goods);
c.setDaemon(True);
p.setDaemon(True);
c.start();
p.start();
c.join();
p.join();
3.queue
简单的理解为,生产者(多个)进程向queue的一段装入数据,消费者(多个)进程从另一端取数据,并不是用queue控制进程仅是数据交换的容器
Queue.task_done()
在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号,
主要是关系到Queue.join()阻塞着主进程,当queue空时才会继续
Queue.join() 实际上意味着等到队列为空,再执行别的操作。看来也是一定程度上有些控制了进程。
#coding=utf-8
import queue
import threading
import time
class threadingQueue(threading.Thread):
def __init__(self,name,q):
threading.Thread.__init__(self);
self.name=name;
self.q=q;
def run(self):
while(True):
#time.sleep(5);
#print("%s threading start \n"%self.name);
a=self.q.get();
print('------',a,'-----\n');
self.q.task_done();
if __name__=='__main__':
data=[1,2,3,4,5,6,7,8,9,0];
qTmp=queue.Queue();
for i in data:
qTmp.put(i);
for j in range(3):
t=threadingQueue(str(j),qTmp);
t.setDaemon(True);
t.start();
qTmp.join();
print('All Done !');
#最后的输出都是都是按照队列的顺序来的,没有被破坏,
#但是有趣的是线程间有打断,print时出现交叉
#也可以看出,一个进程负责添加一个进程提出数据也是可以的,
#但是,如果初始queue为空,怎么保证不会出现主进程直接到queue.join()这步直接退出?
3.信号量
信号量维护着一个计数器,指定可同时访问资源或者进入临界区的线程数。信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,其他线程就停止访问信号量,直到另一个线程释放信号量。
#coding=utf-8
import threading
import time
class Num:
def __init__(self):
self.num=0;
def add(self):
self.num +=1;
def get(self):
return self.num;
class threadingSema(threading.Thread):
def __init__(self,s,n):
threading.Thread.__init__(self);
self.s=s;
self.n=n;
def run(self):
#while(True):
self.s.acquire();#内部计数器减1
self.n.add();
print("当前num=",self.n.get());
time.sleep(3);
self.s.release();#内部计数器加1
if __name__=="__main__":
n=Num();
s=threading.Semaphore(3);
threads=[];
for i in range(10):
t=threadingSema(s,n);
t.setDaemon(True);
t.start();
threads.append(t);
for tt in threads:
tt.join();
#这是输出,可以看出是每次三个线程,计算结果也正确,三个同时计算结果也没出错。
#出差的只是输出线程间的打断(这个有办法解决么?)
当前num= 1
当前num= 当前num=2
3
当前num= 4
当前num=当前num= 56
当前num= 7
当前num=当前num= 8
9
当前num= 10
- event
线程间通信的基本功能,更为通用的一种做法是使用threading.Event对象。使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False。一旦该线程通过wait()方法进入等待状态,后面的代码将被阻塞,直到另一个线程调用该Event的set()方法将内置标志设置为True时,该Event会通知所有处于等待状态的线程恢复运行。
#coding=utf-8
import threading,time
class threadingEvent(threading.Thread):
def __init__(self,name,e):
threading.Thread.__init__(self);
self.name=name;
self.e=e;
def run(self):
print("我是%s,我先睡一会\n"%self.name);
self.e.wait();#默认为False,所以阻塞在这了
print("我是%s,我被唤醒了\n"%self.name);
if __name__=='__main__':
event=threading.Event();
for i in range(3):
t=threadingEvent('X'+str(i),event);
t.setDaemon(True);
t.start();
print("sleep 5 seconds\n");
time.sleep(5);
event.set();#置为True,从wait状态恢复运行
t.join();
print("Done !");