多线程编程

来源:互联网 发布:手机怎么申请淘宝介入 编辑:程序博客网 时间:2024/05/21 21:38

1、

当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。每个进程至少都有一个主线程,在Winform中,应该就是创建GUI的线程。

主线程的重要性体现在两方面:1.是产生其他子线程的线程;2.通常它必须最后完成执行比如执行各种关闭动作。

实验代码:

import threadingdef f(i):    print("I am from a thread,num=%d\n"%(i));def main():    for i in range(1,10):        t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int        t.setDaemon(True);        t.start();if __name__=="__main__":    main();

实验结果为:


结论:虽然线程的创建和启动是有顺序的,但线程是并发运行的,所以那个线程先执行完是不确定的。从运行结果可以看到,输出的数字也是没有规律的。而且在“I am from a thread, num=4",前面还有个>>>,是说明主程序在此处已经退出。

线程对象的setDaemon()方法可以让子线程随着主线程的退出而结束,不过注意的是setDaemon()方法必须在线程对象没有调用start()方法之前调用(默认情况下;在python

中,主线程结束后,会默认等待子线程结束后,主线程才退出)。

2、阻塞进程

# -*- coding: cp936 -*-import threadingdef f(i):    print("I am from a thread,num=%d\n"%(i));def main():    for i in range(1,10):        t=threading.Thread(target=f,args=(i,));#TypeError: f() argument after * must be a sequence, not int        t.setDaemon(True);        t.start();    t.join();#可以阻塞进程直到线程执行完毕。if __name__=="__main__":    main();
运行结果为:


可以看到,进程在所有线程结束后才退出。

3、指令锁

当多个线程同时访问同一资源(比如,全局变量),可能会出现访问冲突。

冲突:

import threadingimport timenum=0;def f():    global num;    b=num;    time.sleep(0.0001);    num=b+1;    print('%s\n'%threading.currentThread().getName());def main():    for i in range(1,20):        t=threading.Thread(target=f);        t.setDaemon(True);        t.start();    t.join();    print(num);if __name__=="__main__":    main();

实验结果为:


改进:

可以使用锁来限制线程同时访问同一资源。指令锁处于锁定状态时,不能被特定的线程所拥有。当线程申请一个处于锁定状态的锁时线程会被阻塞,直至该锁被释放。

在访问全局变量之前申请一个指令锁,在访问全局变量之后释放一个指令锁,这样就可以避免多个线程同时访问全局变量。

# -*- coding: cp936 -*-import threadingimport timelock=threading.Lock();#创建一个指令锁num=0;def f():    global num;    if lock.acquire():        print('%s获得指令锁.'%threading.currentThread().getName());        b=num;        time.sleep(0.0001);        num=b+1;        lock.release()#释放指令锁        print('%s释放指令锁.'%threading.currentThread().getName());    print('%s\n'%threading.currentThread().getName());def main():    for i in range(1,20):        t=threading.Thread(target=f);        t.setDaemon(True);        t.start();    t.join();    print(num);if __name__=="__main__":    main();
实验结果:



4、可重入锁

使用指令锁可以避免多个线程同时访问全局变量。但是如果一个线程里面有递归函数,则它可能会多次请求访问全局变量,此时,即使线程已经获得指令锁,在它再次申请

指令锁时会被阻塞。每个可重入锁都关联一个请求计数器和一个占有它的线程,当请求计数器为0时,这个锁可以被一个线程请求得到并把锁的请求计数加1。如果同一个线程

再次请求这个锁,请求计数器就会增加,当该线程释放RLock时,其计数器减1,当计数器为0时,该锁被释放。

实验代码:

# -*- coding: cp936 -*-import threadingimport timelock=threading.RLock();#创建一个可重入锁num=0;def f():    global num;    #第一次请求锁定    if lock.acquire():        print('%s获得指令锁.'%threading.currentThread().getName());        time.sleep(0.0001);        #第二次请求锁定        if lock.acquire():            print('%s获得指令锁.'%threading.currentThread().getName());            time.sleep(0.0001);            lock.release()#释放指令锁            print('%s释放指令锁.'%threading.currentThread().getName());    time.sleep(0.0001);      print('%s释放指令锁.'%threading.currentThread().getName());    lock.release()#释放指令锁def main():    for i in range(1,20):        t=threading.Thread(target=f);        t.setDaemon(True);        t.start();    t.join();    print(num);if __name__=="__main__":    main();

实验结果:

>>> 
Thread-1获得指令锁.
Thread-1获得指令锁.
Thread-1释放指令锁.
Thread-1释放指令锁.
Thread-2获得指令锁.
Thread-2获得指令锁.
Thread-2释放指令锁.
Thread-2释放指令锁.
Thread-3获得指令锁.
Thread-3获得指令锁.
Thread-3释放指令锁.
Thread-3释放指令锁.
Thread-4获得指令锁.
Thread-4获得指令锁.
Thread-4释放指令锁.
Thread-4释放指令锁.
Thread-5获得指令锁.
Thread-5获得指令锁.
Thread-5释放指令锁.
Thread-5释放指令锁.
Thread-6获得指令锁.
Thread-6获得指令锁.
Thread-6释放指令锁.
Thread-6释放指令锁.
Thread-7获得指令锁.
Thread-7获得指令锁.
Thread-7释放指令锁.
Thread-7释放指令锁.
Thread-8获得指令锁.
Thread-8获得指令锁.
Thread-8释放指令锁.
Thread-8释放指令锁.
Thread-9获得指令锁.
Thread-9获得指令锁.
Thread-9释放指令锁.
Thread-9释放指令锁.
Thread-10获得指令锁.
Thread-10获得指令锁.
Thread-10释放指令锁.
Thread-10释放指令锁.
Thread-11获得指令锁.
Thread-11获得指令锁.
Thread-11释放指令锁.
Thread-11释放指令锁.
Thread-12获得指令锁.
Thread-12获得指令锁.
Thread-12释放指令锁.
Thread-12释放指令锁.
Thread-13获得指令锁.
Thread-13获得指令锁.
Thread-13释放指令锁.
Thread-13释放指令锁.
Thread-14获得指令锁.
Thread-14获得指令锁.
Thread-14释放指令锁.
Thread-14释放指令锁.
Thread-15获得指令锁.
Thread-15获得指令锁.
Thread-15释放指令锁.
Thread-15释放指令锁.
Thread-16获得指令锁.
Thread-16获得指令锁.
Thread-16释放指令锁.
Thread-16释放指令锁.
Thread-17获得指令锁.
Thread-17获得指令锁.
Thread-17释放指令锁.
Thread-17释放指令锁.
Thread-18获得指令锁.
Thread-18获得指令锁.
Thread-18释放指令锁.
Thread-18释放指令锁.
Thread-19获得指令锁.
Thread-19获得指令锁.
Thread-19释放指令锁.
Thread-19释放指令锁.
0
>>> 

5、信号量


原创粉丝点击