一、多任务

  多任务简单来说就是操作系统可以同时运行多个任务(同一时间进行多件事)。

并行:真的多任务——多个CPU在同一个时间点执行多个任务;

并发:假的多任务——CPU交替在同一时间段执行多个任务,并不是同时执行,只是因为CPU执行的速度过快,使得人们感到是在“同时”执行,执行的先后顺序取决于各个程序对于时间片资源的争夺;

几乎所有的操作系统都支持同时运行多个任务,每个任务通常是一个程序,每一个运行中的程序就是一个进程,即进程是应用程序的执行实例。现代的操作系统几乎都支持多进程并发执行。

并发和并行是两个概念,并行指在同一时刻有多条指令在多个处理器上同时执行;并发是指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

但事实的真相是,对于一个 CPU 而言,在某个时间点它只能执行一个程序。也就是说,只能运行一个进程,CPU 不断地在这些进程之间轮换执行。那么,为什么用户感觉不到任何中断呢?
这是因为相对人的感觉来说,对于一个 CPU 而言,在某个时间点它只能执行一个程序。也就是说,只能运行一个进程,CPU 不断地在这些进程之间轮换执行。那么,为什么用户感觉不到任何中断呢?

这是因为相对人的感觉来说,CPU 的执行速度太快了(如果启动的程序足够多,则用户依然可以感觉到程序的运行速度下降了)。所以,虽然 CPU 在多个进程之间轮换执行,但用户感觉到好像有多个进程在同时执行。
线程是进程的组成部分,一个进程可以拥有多个线程。在多线程中,会有一个主线程来完成整个进程从开始到结束的全部操作,而其他的线程会在主线程的运行过程中被创建或退出。
当进程被初始化后,主线程就被创建了,对于绝大多数的应用程序来说,通常仅要求有一个主线程,但也可以在进程内创建多个顺序执行流,这些顺序执行流就是线程。

当一个进程里只有一个线程时,叫作单线程。超过一个线程就叫作多线程。

每个线程必须有自己的父进程,且它可以拥有自己的堆栈、程序计数器和局部变量,但不拥有系统资源,因为它和父进程的其他线程共享该进程所拥有的全部资源。线程可以完成一定的任务,可以与其他线程共享父进程中的共享变量及部分环境,相互之间协同完成进程所要完成的任务。

多个线程共享父进程里的全部资源,会使得编程更加方便,需要注意的是,要确保线程不会妨碍同一进程中的其他线程。

线程是独立运行的,它并不知道进程中是否还有其他线程存在。线程的运行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行。

多线程也是并发执行的,即同一时刻,Python 主程序只允许有一个线程执行,这和全局解释器锁有关系,

一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发运行。

从逻辑的角度来看,多线程存在于一个应用程序中,让一个应用程序可以有多个执行部分同时执行,但操作系统无须将多个线程看作多个独立的应用,对多线程实现调度和管理以及资源分配,线程的调度和管理由进程本身负责完成。

简而言之,进程和线程的关系是这样的:操作系统可以同时执行多个任务,每一个任务就是一个进程,进程可以同时执行多个任务,每一个任务就是一个线程。

  】

【下面 转自别人】

    打个比方。并发,就像一个人(cpu)喂2个孩子(程序),轮换着每人喂一口,表面上两个孩子都在吃饭。并行,就是2个人喂2个孩子,两个孩子也同时在吃饭。

二、线程

线程(有时候成为轻量级进程),他们是在同一个进程之下执行的,并共享相同的上下文;

   线程包括开始,执行顺序和结束三个部分。它有一个指令指针,用于记录当前运行的上下文。当其他县城运行时,它可以被抢占(中断)和临时挂起(也称为睡眠)——这样的做法叫做让步。

  一个进程中的各个线程和主线程共享一片数据空间,因此相比于独立的进程而言,线程间的信息共享和通信更加容易。线程一般是以并发方式进行的,正是因为这种并发和数据共享机制,是的多任务间的协作成为可能。当然,在单核CPU系统中,真正的并发是不可能的,所以是这样运行的:每个线程运行一会儿,然后让步给其他进程(再次排队等待更多的CPU时间)。

   当然,这样的共享并不是没有风险的。如果两个或者多个线程访问同一片数据,由于数据的访问顺序不同,可能导致的结果也是不一样的,这种情况通常称为竞态条件。

   线程无法给予公平的执行时间,这个是因为一些函数会在完成前保持阻塞状态,如果没有专门为多线程情况进行修改,会导致CPU的时间分配向这些贪婪的函数倾斜。

线程执行是没有先后顺序的。

 

  • function - 线程函数。
  • args - 传递给线程函数的参数,他必须是个tuple类型。

 

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

def sing():
    for i in range(5):
        print("————第%d秒正在唱歌——" %i)
        time.sleep(1)


def dance():
    for i in range(5):
        print("————第%d秒正在跳舞——" %i)
        time.sleep(1)


def main():
    t1=threading.Thread(target=sing)
    t2=threading.Thread(target=dance)
    t1.start()
    t2.start()

if __name__ == '__main__':
    main()


#############################
————第0秒正在唱歌——
————第0秒正在跳舞——
————第1秒正在跳舞——
————第1秒正在唱歌——
————第2秒正在唱歌——
————第2秒正在跳舞——
————第3秒正在唱歌——
————第3秒正在跳舞——
————第4秒正在唱歌——
————第4秒正在跳舞——

View Code

  让某些线程先执行:

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

def test1():
    for i in range(5):
        print("————test1—%d—" %i)
        time.sleep(1)


def test2():
    for i in range(5):
        print("————test2—%d—" %i)
        time.sleep(1)


def main():
    t1=threading.Thread(target=test1)
    t2=threading.Thread(target=test2)
    t1.start()
    time.sleep(1)
    print("——1————————————")
    t2.start()
    time.sleep(1)
    print("——2————————————")

    print(threading.enumerate())

if __name__ == '__main__':
    main()


################################
————test1—0—
————test1—1—
——1————————————
————test2—0—
————test2—1—
————test1—2—
——2————————————
[<Thread(Thread-1, started 4380)>, <_MainThread(MainThread, started 7052)>, <Thread(Thread-2, started 6660)>]
————test2—2—
————test1—3—
————test2—3—
————test1—4—
————test2—4—

View Code

  循环查看当前执行的线程:

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

def test1():
    for i in range(5):
        print("————test1—%d—" %i)
        time.sleep(1)


def test2():
    for i in range(5):
        print("————test2—%d—" %i)
        time.sleep(1)


def main():
    t1=threading.Thread(target=test1)
    t2=threading.Thread(target=test2)
    t1.start()
    time.sleep(1)
    print("——1————————————")
    t2.start()
    time.sleep(1)
    print("——2————————————")

    while True:
        print(threading.enumerate())
        if len(threading.enumerate())<=1:
            break
        time.sleep(1)

if __name__ == '__main__':
    main()

##################################
————test1—0—
————test1—1—
——1————————————
————test2—0—
————test2—1—
————test1—2—
——2————————————
[<Thread(Thread-2, started 6224)>, <Thread(Thread-1, started 6436)>, <_MainThread(MainThread, started 1300)>]
————test1—3—
————test2—2—
[<Thread(Thread-2, started 6224)>, <Thread(Thread-1, started 6436)>, <_MainThread(MainThread, started 1300)>]
————test2—3—
————test1—4—
[<Thread(Thread-2, started 6224)>, <Thread(Thread-1, started 6436)>, <_MainThread(MainThread, started 1300)>]
————test2—4—
[<Thread(Thread-2, started 6224)>, <_MainThread(MainThread, started 1300)>]
[<_MainThread(MainThread, started 1300)>]

View Code

  验证创建线程以及运行时间:

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading


def test():
    for i in range(5):
        print("————%d——" %i)


def main():
    print(threading.enumerate())
    t=threading.Thread(target=test)
    print(threading.enumerate())
    t.start()
    print("*"*100)
    print(threading.enumerate())
#结论:当调用Thread的时候,不会创建线程;
#       当调用Thread创建出来的实例对象的start方法的时候,才会创建线程以及让这个线程开始运行
#        线程结束是有函数决定,函数结束,线程结束
#        子线程先结束,主线程最后结束

if __name__ == '__main__':
    main()

##############################
[<_MainThread(MainThread, started 4132)>]
[<_MainThread(MainThread, started 4132)>]
————0——
****************************************************************************************************
[<Thread(Thread-1, started 4868)>, <_MainThread(MainThread, started 4132)>]
————1——
————2——
————3——
————4——

View Code

  创建线程的第二种方法:

  通过继承Thread类创建线程:

  通过继承 Thread 类来创建并启动线程的步骤如下:

  1. 定义 Thread 类的子类,并重写该类的 run() 方法。run() 方法的方法体就代表了线程需要完成的任务,因此把 run() 方法称为线程执行体。
  2. 创建 Thread 子类的实例,即创建线程对象。
  3. 调用线程对象的 start() 方法来启动线程。

 

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import  time
import threading

class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            time.sleep(1)
            #name苏醒中保存的是当前线程的名字
            msg="我是"+self.name+"@"+str(i)
            print(msg)

if __name__ == '__main__':
    print(threading.enumerate())
    t=MyThread()#创建类对象
    #t=threading.Thread(target=test)
    #target=函数名
    t.start()
    print(threading.enumerate())


#######################
[<_MainThread(MainThread, started 1124)>]
[<MyThread(Thread-1, started 1504)>, <_MainThread(MainThread, started 1124)>]
我是Thread-1@0
我是Thread-1@1
我是Thread-1@2
我是Thread-1@3
我是Thread-1@4

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import  time
import threading

class MyThread(threading.Thread):
    def run(self):
        self.eat()
        self.bark()
        for i in range(5):
            time.sleep(1)
            #name苏醒中保存的是当前线程的名字
            msg="我是"+self.name+"@"+str(i)
            print(msg)


    def eat(self):
        print("这个是吃的方法")

    def bark(self):
        print("这个是叫的方法")
if __name__ == '__main__':
    print(threading.enumerate())
    t=MyThread()#创建类对象
    #t=threading.Thread(target=test)
    #target=函数名
    t.start()#类中必须要有run方法
    print(threading.enumerate())

##############################
[<_MainThread(MainThread, started 2752)>]
这个是吃的方法
[<_MainThread(MainThread, started 2752)>, <MyThread(Thread-1, started 3800)>]
这个是叫的方法
我是Thread-1@0
我是Thread-1@1
我是Thread-1@2
我是Thread-1@3
我是Thread-1@4

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import  time
import threading

class MyThread(threading.Thread):
    # def run(self):
    #     self.eat()
    #     self.bark()
    #     for i in range(5):
    #         time.sleep(1)
    #         #name苏醒中保存的是当前线程的名字
    #         msg="我是"+self.name+"@"+str(i)
    #         print(msg)


    def eat(self):
        print("这个是吃的方法")

    def bark(self):
        print("这个是叫的方法")
if __name__ == '__main__':
    print(threading.enumerate())
    t=MyThread()#创建类对象
    #t=threading.Thread(target=test)
    #target=函数名
    t.start()#类中必须要有run方法
    print(threading.enumerate())


##############################
[<_MainThread(MainThread, started 4600)>]
[<_MainThread(MainThread, started 4600)>]

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

mport threading
def func(num):
    for i in range(num):
        print(threading.current_thread().getName()+''+str(i))

for i in range(5):
    if i==3:
        t1=threading.Thread(target=func,args=(5,))
        t1.start()

        t2 = threading.Thread(target=func, args=(10,))
        t2.start()


'''
threading.current_thread():它是 threading 模块的函数,该函数总是返回当前正在执行的线程对象。
getName():它是 Thread 类的实例方法,该方法返回调用它的线程名字。

在 Threading 模块中,除了 current_thread() 函数外,还经常使用如下 2 个函数:
threading.enumerate():返回一个正运行线程的 list。“正运行”是指线程处于“启动后,且在结束前”状态,不包括“启动前”和“终止后”状态。
threading.activeCount():返回正在运行的线程数量。与

View Code

    虽然上面程序只显式创建并启动了两个线程,但实际上程序有三个线程,即程序显式创建的两个子线程和主线程。前面己经提到,当 Python 程序开始运行后,程序至少会创建一个主线程,主线程的线程执行体就是程序中的主程序(没有放在任何函数中的代码)

  注意,启动线程使用 start() 方法,而不是 run() 方法。调用 start() 方法来启动线程,系统会把该 run() 方法当成线程执行体来处理;但如果直接调用线程对象的 run() 方法,则 run() 方法立即就会被执行,而且在该方法返回之前其他线程无法并发执行。也就是说,如果直接调用线程对象的 run() 方法,则系统会把线程对象当成一个普通对象,而 run() 方法是一个普通方法,不是线程执行体。

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

import threading
def func(num):
    for i in range(num):
        print(threading.current_thread().getName()+''+str(i))

for i in range(5):
    if i==3:
        # 直接调用线程对象的run()方法
        # 系统会把线程对象当成普通对象,把run()方法当成普通方法
        # 所以下面两行代码并不会启动两个线程,而是依次执行两个run()方法
        t1=threading.Thread(target=func,args=(5,)).run()
        # t1.start()

        t2 = threading.Thread(target=func, args=(10,)).run()
        # t2.start()

View Code

 直接调用了线程对象的 run() 方法,程序运行的结果是整个程序只有一个主线程。还有一点需要指出,如果直接调用线程对象的 run() 方法,则在 run() 方法中不能直接通过 name 属性(getName() 方法)来获取当前执行线程的名字,而是需要使用 threading.current_thread() 函数先获取当前线程,然后再调用线程对象的 name 属性来获取线程的名字。

  线程的新建和就绪状态:

新建状态,不要再次调用线程对象的 start() 方法。在调用线程对象的 run() 方法之后,该线程己经不再处于新建状态,不要再次调用线程对象的 start() 方法。在调用线程对象的 start() 方法之后,该线程立即进入就绪状态(相当于“等待执行”),但该线程并未真正进入运行状态。

 线程的运行和堵塞状态:

    如果处于就绪状态的线程获得了 CPU,开始执行 run() 方法的线程执行体,则该线程处于运行状态。

如果计算机只有一个 CPU,那么在任何时刻只有一个线程处于运行状态。当然,在一个具有多处理器的机器上,将会有多个线程并行(Parallel)执行;当线程数大于处理器数时,依然会存在多个线程在同一个 CPU 上轮换的情况。

当一个线程开始运行后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就执行结束了),线程在运行过程中需要被中断,目的是使其他线程获得执行的机会,线程调度的细节取决于底层平台所采用的策略。对于采用抢占式调度策略的系统而言,系统会给每一个可执行的线程一个小时间段来处理任务;当该时间段用完后,系统就会剥夺该线程所占用的资源,让其他线程获得执行的机会。在选择下一个线程时,系统会考虑线程的优先级。

所有现代的桌面和服务器操作系统都采用抢占式调度策略,但一些小型设备如手机等则可能采用协作式调度策略,在这样的系统中,只有当一个线程调用了它的 sleep() 或 yield() 方法后才会放弃其所占用的资源(也就是必须由该线程主动放弃其所占用的资源)。

当发生如下情况时,线程将会进入阻塞状态:

  • 线程调用 sleep() 方法主动放弃其所占用的处理器资源。
  • 线程调用了一个阻塞式 I/O 方法,在该方法返回之前,该线程被阻塞。
  • 线程试图获得一个锁对象,但该锁对象正被其他线程所持有。关于锁对象的知识,后面将有更深入的介绍。
  • 线程在等待某个通知(Notify)。

当前正在执行的线程被阻塞之后,其他线程就可以获得执行的机会。被阻塞的线程会在合适的时候重新进入就绪状态,注意是就绪状态,而不是运行状态。也就是说,被阻塞线程的阻塞解除后,必须重新等待线程调度器再次调度它。

针对上面几种情况,当发生如下特定的情况时可以解除阻塞,让该线程重新进入就绪状态:

  • 调用 sleep() 方法的线程经过了指定的时间。
  • 线程调用的阻塞式 I/O 方法己经返回。
  • 线程成功地获得了试图获取的锁对象。
  • 线程正在等待某个通知时,其他线程发出了一个通知。

线程死亡

  线程会以如下方式结束,结束后就处于死亡状态:

  • run() 方法或代表线程执行体的 target 函数执行完成,线程正常结束。
  • 线程抛出一个未捕获的 Exception 或 Error。

  注意,当主线程结束时,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,不会受主线程的影响。

  为了测试某个线程是否己经死亡,可以调用线程对象的 is_alive() 方法,当线程处于就绪、运行、阻塞三种状态时,该方法将返回 True;当线程处于新建、死亡两种状态时,该方法将返回 False。

  不要试图对一个已经死亡的线程调用 start() 方法使它重新启动,死亡就是死亡,该线程将不可再次作为线程运行。 

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

# 定义action函数准备作为线程执行体使用
def func(max):
    for  i in range(50):
        print(threading.current_thread().name +  " " + str(i))
# 创建线程对象
t = threading.Thread(target=func, args=(100,))
for i in range(100):
    # 调用threading.current_thread()函数获取当前线程
    print(threading.current_thread().name +  " " + str(i))
    if i == 20:
        # 启动线程
        t.start()
        # 判断启动后线程的is_alive()值,输出True
        print(t.is_alive())
    # 当线程处于新建、死亡两种状态时,is_alive()方法返回False
    # 当i > 20时,该线程肯定已经启动过了,如果sd.is_alive()为False时
    # 那就是死亡状态了
    # if i > 50 and not(sd.is_alive()):
    #     # 试图再次启动该线程
    #     t.start()

View Code

 

 

 

多线程共享全局变量:

rxjava多任务并发 多线程多任务并行_多线程_21

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=50
def test1():
    global g_num
    g_num+=1
    print("=======test1——g_num=%d" %g_num)


def test2():
    print("=======test2——g_num=%d" %g_num)


def main():
    t1=threading.Thread(target=test1)
    t2=threading.Thread(target=test2)

    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)
    print(g_num)

if __name__ == '__main__':
    main()

#####################
=======test1——g_num=51
=======test2——g_num=51
51

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=[11,22,33,44]
def test1(temp):
    temp.append(555)
    print("=======test1——temp=%s" %str(temp))


def test2(temp):
    print("=======test2——temp=%s" %str(temp))


def main():
    t1=threading.Thread(target=test1,args=(g_num,))#元祖里面的逗号不能少
    t2=threading.Thread(target=test2,args=(g_num,))

    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)
    print(g_num)

if __name__ == '__main__':
    main()


##################################
=======test1——temp=[11, 22, 33, 44, 555]
=======test2——temp=[11, 22, 33, 44, 555]
[11, 22, 33, 44, 555]

View Code

 

  共享全局变量问题——资源竞争

  多线程的优势在于并发性,即可以同时运行多个任务。但是当线程需要使用共享数据时,也可能会由于数据不同步产生“错误情况”,【注意,此处说的是有可能,并不是一定】这是由系统的线程调度具有一定的随机性造成的。

互斥锁的作用就是解决数据不同步问题。

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=0
def test1(temp):
    for i in range(temp):
        global g_num
        g_num+=1
    print("=======test1——g_num=%d" %g_num)


def test2(temp):
    for i in range(temp):
        global g_num
        g_num+=1
    print("=======test2——g_num=%d" %g_num)



def main():
    t1=threading.Thread(target=test1,args=(100,))
    t2=threading.Thread(target=test2,args=(100,))

    t1.start()
    t2.start()
    time.sleep(5)
    print(g_num)

if __name__ == '__main__':
    main()

##################
=======test1——g_num=100
=======test2——g_num=200
200

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=0
def test1(temp):
    for i in range(temp):
        global g_num
        g_num+=1
    print("=======test1——g_num=%d" %g_num)


def test2(temp):
    for i in range(temp):
        global g_num
        g_num+=1
    print("=======test2——g_num=%d" %g_num)



def main():
    t1=threading.Thread(target=test1,args=(1000000,))
    t2=threading.Thread(target=test2,args=(1000000,))

    t1.start()
    t2.start()
    time.sleep(5)
    print(g_num)

if __name__ == '__main__':
    main()
############################
=======test2——g_num=1177009
=======test1——g_num=1192154
1192154

View Code

 

  解决资源竞争问题:

   互斥锁:【转自别人】

    当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制;

    线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

    也就是换句话说,在多线程时,保证修改共享数据时是有序的修改,不会产生数据修改的混乱。

    某个线程要更改共享数据是,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;知道该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入 操作,从而拨正了多线程情况下的数据的正确性。

  

  上锁解锁过程:

    当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。

    每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。

    线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

    

  总结:

    锁的好处:

      确保了某段关键代码只能由一个线程从头到尾完整地执行。

    锁的坏处:

      阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了;

      由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁。

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=0
#创建一个互斥锁,默认是没有上锁的
mutex=threading.Lock()


def test1(temp):
    global g_num
    #上锁,如果之前没有被上锁,那么此时上锁成功
    #如果上锁之前,已经被上锁了,那么此时会堵塞在这里,直到这个所被揭开
    mutex.acquire()
    for i in range(temp):
        g_num+=1
        #  解锁
    mutex.release()
    print("=======test1——g_num=%d" %g_num)


def test2(temp):
    global g_num
    mutex.acquire()
    for i in range(temp):
        g_num+=1
    mutex.release()
    print("=======test2——g_num=%d" %g_num)



def main():
    t1=threading.Thread(target=test1,args=(1000000,))
    t2=threading.Thread(target=test2,args=(1000000,))

    t1.start()
    t2.start()
    time.sleep(2)
    print(g_num)

if __name__ == '__main__':
    main()

###############################
=======test1——g_num=1000000
=======test2——g_num=2000000
2000000

View Code

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import time
import threading

g_num=0
#创建一个互斥锁,默认是没有上锁的
mutex=threading.Lock()


def test1(temp):
    global g_num
    #上锁,如果之前没有被上锁,那么此时上锁成功
    #如果上锁之前,已经被上锁了,那么此时会堵塞在这里,直到这个所被揭开

    for i in range(temp):
        mutex.acquire()
        g_num+=1
        #  解锁
        mutex.release()
    print("=======test1——g_num=%d" %g_num)


def test2(temp):
    global g_num
    mutex.acquire()
    for i in range(temp):
        g_num+=1
    mutex.release()
    print("=======test2——g_num=%d" %g_num)


def main():
    t1=threading.Thread(target=test1,args=(1000000,))
    t2=threading.Thread(target=test2,args=(1000000,))

    t1.start()
    t2.start()
    time.sleep(2)
    print(g_num)

if __name__ == '__main__':
    main()


##################################
=======test2——g_num=1015809
=======test1——g_num=2000000
2000000

View Code

 

 死锁:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。——来自百度百科

 

rxjava多任务并发 多线程多任务并行_主线程

rxjava多任务并发 多线程多任务并行_Code_02

__author__ = 'Administrator'
import socket
import threading


def recv_msg(udp_socket):
    while True:
        #  3.接收数据
        recv_data=udp_socket.recvfrom(1024)
        print(recv_data)

def send_msg(udp_socket,dest_ip,dest_port):
    while True:
        #  4.发送数据
        send_data=input("请输入想要发送的信息:")
        udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))

def main():
    #  1.创建套接字
    udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    #  2.绑定ip和port
    dest_ip=input("请输入要链接的对方的ip:")
    dest_port=int(input("请输入要链接的对方的端口号:"))

    #创建线程
    t_recv_msg=threading.Thread(target=recv_msg,args=(udp_socket,))
    t_send_msg=threading.Thread(target=send_msg,args=(udp_socket,dest_ip,dest_port,))

    t_recv_msg.start()
    t_send_msg.start()

if __name__ == '__main__':
    main()

View Code

 

 

 

__author__ = 'Administrator'
import time
import threading

g_num=[11,22,33,44]
def test1(temp):
    temp.append(555)
    print("=======test1——temp=%s" %str(temp))


def test2(temp):
    print("=======test2——temp=%s" %str(temp))


def main():
    t1=threading.Thread(target=test1,args=(g_num,))
    t2=threading.Thread(target=test2,args=(g_num,))

    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)
    print(g_num)

if __name__ == '__main__':
    main()