Python多线程

我想干点什么呢?有点目的性才有做下去的动力!


  • 多线程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拥有自己的可自定义线程类
.共享数据,线程同步
数据共享。当多个线程都要去修改某一个共享数据的时候,我们需要对数据访问进行同步。


  1. 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

  1. 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 !");

你可能感兴趣的:(Python多线程)