多线程修改同一个数据

个人理解:

  GIL:存在于Cpython中,称为全局解释器锁,在同一时间只能一个python线程在跑,但这并不是说是串行运行的,他还是“并行”的,CPU在不断的分配cpu时间给每个线程去运行,只是同一时间刻只有一个线程在跑。

  线程锁:只让一个线程运行加锁的那段代码。

示例:

1 print(n)
2 n += 1
3 print(n)
4 # 这里三条语句需要三次获取n的值,第一次print(n)和 n += 1时拿到的n 不一定相同,第二次print(n)也不一定是 n += 1的结果。 但 n += 1的操作是原子性的,执行n += 1过程中,从拿到n 再 n + 1再重新赋值给n的这个过程中,其他线程不能修改,且也不能访问n的值

  

简单示例1:

import threading
import time

def f(i):
    global n
    time.sleep(1)
    print("begin += 1:  i=%s,n=%s"%(i,n))
    n += 1
    print("end +=1:     i=%s,n=%s"%(i,n))

if __name__ == "__main__":
    t_list = []
    n = 0
    for i in range(100):
        t = threading.Thread(target=f,args=(i,))
        t.start()
        t_list.append(t)

    for i in t_list:
        i.join()

执行结果:

begin += 1:  i=2,n=0
end +=1:     i=2,n=1
begin += 1:  i=1,n=1
end +=1:     i=1,n=2
begin += 1:  i=0,n=2
end +=1:     i=0,n=3
begin += 1:  i=4,n=3
end +=1:     i=4,n=4
begin += 1:  i=3,n=4
end +=1:     i=3,n=5
begin += 1:  i=6,n=5
end +=1:     i=6,n=6
begin += 1:  i=5,n=6
end +=1:     i=5,n=7
begin += 1:  i=9,n=7
begin += 1:  i=8,n=7
begin += 1:  i=7,n=7
end +=1:     i=7,n=8
end +=1:     i=8,n=9
end +=1:     i=9,n=10
begin += 1:  i=13,n=10
end +=1:     i=13,n=11
begin += 1:  i=15,n=11
begin += 1:  i=12,n=11
begin += 1:  i=11,n=11
end +=1:     i=12,n=12
begin += 1:  i=14,n=12
end +=1:     i=14,n=13
begin += 1:  i=10,n=13
end +=1:     i=11,n=14
begin += 1:  i=16,n=14
end +=1:     i=16,n=15
end +=1:     i=10,n=16
end +=1:     i=15,n=17
begin += 1:  i=19,n=17
end +=1:     i=19,n=18
begin += 1:  i=18,n=18
begin += 1:  i=17,n=18
end +=1:     i=18,n=19
end +=1:     i=17,n=20
begin += 1:  i=21,n=20
end +=1:     i=21,n=21
begin += 1:  i=22,n=20
end +=1:     i=22,n=22
begin += 1:  i=20,n=22
end +=1:     i=20,n=23
begin += 1:  i=24,n=23
end +=1:     i=24,n=24
begin += 1:  i=23,n=24
end +=1:     i=23,n=25
begin += 1:  i=25,n=24
end +=1:     i=25,n=26
begin += 1:  i=28,n=26
end +=1:     i=28,n=27
begin += 1:  i=27,n=27
begin += 1:  i=26,n=27
end +=1:     i=26,n=28
end +=1:     i=27,n=29
begin += 1:  i=29,n=29
end +=1:     i=29,n=30
begin += 1:  i=37,n=30
begin += 1:  i=36,n=30
end +=1:     i=36,n=31
begin += 1:  i=34,n=31
end +=1:     i=34,n=32
begin += 1:  i=33,n=32
end +=1:     i=33,n=33
begin += 1:  i=31,n=33
end +=1:     i=31,n=34
begin += 1:  i=30,n=34
begin += 1:  i=35,n=34
end +=1:     i=35,n=35
end +=1:     i=30,n=36
end +=1:     i=37,n=37
begin += 1:  i=40,n=37
end +=1:     i=40,n=38
begin += 1:  i=32,n=38
end +=1:     i=32,n=39
begin += 1:  i=39,n=39
end +=1:     i=39,n=40
begin += 1:  i=38,n=40
end +=1:     i=38,n=41
begin += 1:  i=42,n=41
begin += 1:  i=41,n=42
end +=1:     i=41,n=43
end +=1:     i=42,n=42
begin += 1:  i=43,n=43
end +=1:     i=43,n=44
begin += 1:  i=46,n=44
end +=1:     i=46,n=45
begin += 1:  i=45,n=45
end +=1:     i=45,n=46
begin += 1:  i=44,n=46
end +=1:     i=44,n=47
begin += 1:  i=48,n=47
end +=1:     i=48,n=48
begin += 1:  i=47,n=48
end +=1:     i=47,n=49
begin += 1:  i=50,n=49
end +=1:     i=50,n=50
begin += 1:  i=51,n=50
end +=1:     i=51,n=51
begin += 1:  i=49,n=51
end +=1:     i=49,n=52
begin += 1:  i=53,n=52
begin += 1:  i=52,n=52
end +=1:     i=53,n=53
end +=1:     i=52,n=54
begin += 1:  i=54,n=54
end +=1:     i=54,n=55
begin += 1:  i=55,n=55
end +=1:     i=55,n=56
begin += 1:  i=56,n=56
end +=1:     i=56,n=57
begin += 1:  i=57,n=57
end +=1:     i=57,n=58
begin += 1:  i=59,n=58
end +=1:     i=59,n=59
begin += 1:  i=58,n=59
end +=1:     i=58,n=60
begin += 1:  i=60,n=60
end +=1:     i=60,n=61
begin += 1:  i=62,n=61
end +=1:     i=62,n=62
begin += 1:  i=61,n=62
end +=1:     i=61,n=63
begin += 1:  i=65,n=63
begin += 1:  i=64,n=63
end +=1:     i=64,n=64
end +=1:     i=65,n=65
begin += 1:  i=63,n=65
end +=1:     i=63,n=66
begin += 1:  i=67,n=66
end +=1:     i=67,n=67
begin += 1:  i=68,n=67
end +=1:     i=68,n=68
begin += 1:  i=66,n=68
end +=1:     i=66,n=69
begin += 1:  i=70,n=69
end +=1:     i=70,n=70
begin += 1:  i=69,n=70
end +=1:     i=69,n=71
begin += 1:  i=73,n=71
begin += 1:  i=72,n=71
end +=1:     i=72,n=72
end +=1:     i=73,n=73
begin += 1:  i=71,n=72
end +=1:     i=71,n=74
begin += 1:  i=74,n=74
end +=1:     i=74,n=75
begin += 1:  i=75,n=75
end +=1:     i=75,n=76
begin += 1:  i=76,n=76
end +=1:     i=76,n=77
begin += 1:  i=77,n=77
end +=1:     i=77,n=78
begin += 1:  i=78,n=78
end +=1:     i=78,n=79
begin += 1:  i=79,n=79
begin += 1:  i=80,n=79
end +=1:     i=80,n=80
end +=1:     i=79,n=81
begin += 1:  i=82,n=81
end +=1:     i=82,n=82
begin += 1:  i=81,n=82
end +=1:     i=81,n=83
begin += 1:  i=84,n=83
begin += 1:  i=85,n=83
end +=1:     i=85,n=84
end +=1:     i=84,n=85
begin += 1:  i=83,n=85
end +=1:     i=83,n=86
begin += 1:  i=86,n=86
end +=1:     i=86,n=87
begin += 1:  i=87,n=87
begin += 1:  i=88,n=87
end +=1:     i=87,n=88
end +=1:     i=88,n=89
begin += 1:  i=90,n=89
end +=1:     i=90,n=90
begin += 1:  i=89,n=90
end +=1:     i=89,n=91
begin += 1:  i=93,n=91
end +=1:     i=93,n=92
begin += 1:  i=91,n=92
end +=1:     i=91,n=93
begin += 1:  i=92,n=93
end +=1:     i=92,n=94
begin += 1:  i=94,n=94
end +=1:     i=94,n=95
begin += 1:  i=95,n=95
end +=1:     i=95,n=96
begin += 1:  i=96,n=96
begin += 1:  i=97,n=96
end +=1:     i=97,n=97
end +=1:     i=96,n=98
begin += 1:  i=99,n=98
begin += 1:  i=98,n=98
end +=1:     i=98,n=99
end +=1:     i=99,n=100

这里可以看到第99次中第一次print(n)获取的值为98,第二次print(n)的值为100。说明执行n += 1时(即n = n + 1)右边的n的值不一定是98。

简单示例2:

import threading
import time

def f(i):
    global n
    time.sleep(1)
    print("begin += 1:  i=%s,n=%s,d=%s"%(i,n,d))
    d[n] ,n = n+1,n+1
    print("end +=1:     i=%s,n=%s,d=%s"%(i,n,d))

if __name__ == "__main__":
    t_list = []
    n = 0
    d = {}
    for i in range(10):
        t = threading.Thread(target=f,args=(i,))
        t.start()
        t_list.append(t)

    for i in t_list:
        i.join()

运行结果:

begin += 1:  i=0,n=0,d={}
begin += 1:  i=1,n=0,d={}
end +=1:     i=1,n=1,d={0: 1}
end +=1:     i=0,n=2,d={0: 1, 1: 2}
begin += 1:  i=5,n=2,d={0: 1, 1: 2}
begin += 1:  i=4,n=2,d={0: 1, 1: 2}
end +=1:     i=4,n=3,d={0: 1, 1: 2, 2: 3}
end +=1:     i=5,n=4,d={0: 1, 1: 2, 2: 3, 3: 4}
begin += 1:  i=2,n=4,d={0: 1, 1: 2, 2: 3, 3: 4}
end +=1:     i=2,n=5,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
begin += 1:  i=3,n=5,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
end +=1:     i=3,n=6,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6}
begin += 1:  i=6,n=6,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6}
end +=1:     i=6,n=7,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7}
begin += 1:  i=9,n=7,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7}
begin += 1:  i=8,n=7,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7}
end +=1:     i=8,n=8,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8}
begin += 1:  i=7,n=8,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8}
end +=1:     i=7,n=9,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9}
end +=1:     i=9,n=10,d={0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}

这里可以看到d[n], n = n+1, n+1是原子性的,这里先是d[n]和右边的两个n获取值,然后分别赋值给d[n]和n,这里不可能出现d[n]和右边的两个n获取的值是8,而在赋值d[n]和n时赋的值是10.

python2.7:

不加线程锁时,n += 1操作时,多个线程能同时访问n获取n的值,这样就会导致多个线程运行n += 1后n的值并不是 n + 1的次数。

import threading
import time

def f(i):
    global n
    time.sleep(1)
    # print("begin += 1:  i=%s,n=%s"%(i,n))
    d[i] , n = "%s:%s"%(n,n +1),n+1
    # print("end +=1:     i=%s,n=%s"%(i,n))

if __name__ == "__main__":
    t_list = []
    n = 0
    d= {}
    for i in range(100):
        t = threading.Thread(target=f,args=(i,))
        t.start()
        t_list.append(t)

    for i in t_list:
        i.join()
    time.sleep(2)

    for i,v in d.items():
        print(i,v)
    print("n=",n)

运行结果:

(0, ‘1:2‘)
(1, ‘0:1‘)
(2, ‘3:4‘)
(3, ‘2:3‘)
(4, ‘5:6‘)
(5, ‘4:5‘)
(6, ‘7:8‘)
(7, ‘6:7‘)
(8, ‘6:7‘)
(9, ‘8:9‘)
(10, ‘7:8‘)
(11, ‘10:11‘)
(12, ‘9:10‘)
(13, ‘11:12‘)
(14, ‘12:13‘)
(15, ‘13:14‘)
(16, ‘15:16‘)
(17, ‘14:15‘)
(18, ‘17:18‘)
(19, ‘16:17‘)
(20, ‘19:20‘)
(21, ‘18:19‘)
(22, ‘21:22‘)
(23, ‘20:21‘)
(24, ‘22:23‘)
(25, ‘23:24‘)
(26, ‘26:27‘)
(27, ‘25:26‘)
(28, ‘24:25‘)
(29, ‘27:28‘)
(30, ‘27:28‘)
(31, ‘31:32‘)
(32, ‘30:31‘)
(33, ‘29:30‘)
(34, ‘32:33‘)
(35, ‘34:35‘)
(36, ‘33:34‘)
(37, ‘36:37‘)
(38, ‘35:36‘)
(39, ‘38:39‘)
(40, ‘37:38‘)
(41, ‘40:41‘)
(42, ‘40:41‘)
(43, ‘39:40‘)
(44, ‘43:44‘)
(45, ‘42:43‘)
(46, ‘41:42‘)
(47, ‘44:45‘)
(48, ‘46:47‘)
(49, ‘45:46‘)
(50, ‘47:48‘)
(51, ‘49:50‘)
(52, ‘48:49‘)
(53, ‘50:51‘)
(54, ‘51:52‘)
(55, ‘52:53‘)
(56, ‘54:55‘)
(57, ‘53:54‘)
(58, ‘56:57‘)
(59, ‘55:56‘)
(60, ‘57:58‘)
(61, ‘57:58‘)
(62, ‘60:61‘)
(63, ‘59:60‘)
(64, ‘61:62‘)
(65, ‘62:63‘)
(66, ‘64:65‘)
(67, ‘65:66‘)
(68, ‘63:64‘)
(69, ‘72:73‘)
(70, ‘71:72‘)
(71, ‘73:74‘)
(72, ‘70:71‘)
(73, ‘69:70‘)
(74, ‘66:67‘)
(75, ‘68:69‘)
(76, ‘67:68‘)
(77, ‘75:76‘)
(78, ‘74:75‘)
(79, ‘76:77‘)
(80, ‘78:79‘)
(81, ‘77:78‘)
(82, ‘80:81‘)
(83, ‘79:80‘)
(84, ‘82:83‘)
(85, ‘81:82‘)
(86, ‘85:86‘)
(87, ‘83:84‘)
(88, ‘84:85‘)
(89, ‘87:88‘)
(90, ‘86:87‘)
(91, ‘89:90‘)
(92, ‘88:89‘)
(93, ‘92:93‘)
(94, ‘91:92‘)
(95, ‘90:91‘)
(96, ‘94:95‘)
(97, ‘93:94‘)
(98, ‘96:97‘)
(99, ‘95:96‘)
(‘n=‘, 97)

这里可以看到线程7和8,29和30,60和61分别获取了同一份n的值。

时间: 2024-12-29 06:54:21

多线程修改同一个数据的相关文章

Redis:多线程修改同一个Key使用watch+事务(mutil)实现乐观锁

本篇文章是通过watch(监控)+mutil(事务)实现应用于在分布式高并发处理等相关场景.下边先通过redis-cli.exe来测试多个线程修改时,遇到问题及解决问题. 高并发下修改同一个key遇到的问题: 1)定义一个hash类型的key,key为:lock_test,元素locker的值初始化为0. 2)实现高并发下对locker元素的值递增:定义64个多线程,并发的对lock_test元素locker的值进行修改. package com.dx.es; import java.util.

python多线程读取同一个文件

多线程读取同一个文件,要求不能重复,不能遗漏. 最开始尝试了一种方法(后来实践证明是无效的) 主线程分配给每个读线程需要读取文件中哪些行, 比如线程1读取1-10行,线程2读取11-30行. 然后每个线程通过readline()来读取,读到的行如果不属于本线程的范围,则continue跳过. 实践证明,这若干个线程并没有按照我们期望来读. 我的猜想是,通过open来打开一个文件,多个线程返回的是同一个句柄, 或者一个文件的文件指针只有一个. 经过网上搜索和实践,总结出有以下方法支持多线程读取同一

不要同时使用ReentrantLock类与synchronized关键字锁定会修改同一个资源的不同方法

转自 http://agrael.iteye.com/blog/685840 本文是讲述ReentrantLock类与synchronized关键字同时使用的问题,不是ReentrantLock类与synchronized关键字的教程.     synchronized关键字作为java多线程编程中非常重要的关键字之一,它维护这线程并发中的安全.通常使用synchronized有2种方式. 锁定当前实例 Java代码   //通过方法上使用synchronized达到锁定效果 public sy

线程系列03,多线程共享数据,多线程不共享数据

多线程编程,有时希望每个线程的数据相互隔离互不影响,有时却希望线程间能共享数据,并保持同步.本篇体验多线程共享和不共享数据. □ 多线程不共享数据 对于多线程,CLR到底是怎样为它们分配内存栈空间呢?是"一个萝卜一个坑",每个线程都有自己的栈空间:还是"大树底下好乘凉",所有的线程共享同一个栈空间? 我们让2个线程执行相同的静态方法,用到相同的变量,通过打印变量来求证多线程栈空间的分配情况. class Program { static void Main(stri

c++11 多线程间共享数据 <c++ concurrency in action>

本章主要描述多线程之间共享数据的方法.存在问题.解决方案. 第一部分:mutex在保护共享数据中的使用 1.最简单使用: #include<mutex> std::mutex some_mutex; void func(){ some_mutex.lock(); //访问共享数据 .... some_mutex.unlock(); } 2.向lock_guard推进: 但是不推荐直接使用lock.unlock,因为unlock一定要调用,如果由于你的疏忽或前面的异常将会导致问题,再次利用RAI

多线程编程之数据访问互斥

在多线程存在的环境中,除了堆栈中的临时数据之外,所有的数据都是共享的.如果我们需要线程之间正确地运行,那么务必需要保证公共数据的执行和计算是正确的.简单一点说,就是保证数据在执行的时候必须是互斥的.否则,如果两个或者多个线程在同一时刻对数据进行了操作,那么后果是不可想象的. 保证多线程之间的数据访问互斥,有以下四类方法: (1)关中断 (2)数学互斥方法 (3)操作系统提供的互斥方法 (4)CPU原子操作 下面针对这四种方法进行详细说明: (1)关中断 既然多线程之间的中断切换会导致访问同一数据

oracle特殊恢复-bbed修改某个数据文件头

数据文件头中的scn要与控制文件中的scn一致,数据库才可以open,在open过程中我们可以通过bbed来修改某个数据文件头的scn,来欺骗oracle,来open库. 1.环境如下 使用Oracle 11gR2进行测试,具体版本为11.2.0.4 [email protected] SQL>select file#,name,checkpoint_change#,checkpoint_time from v$datafile;      FILE# NAME                 

nodejs 通过 get获取数据修改redis数据

如下代码是没有报错的正确代码 我通过https获取到数据 想用redis set一个键值存储 现在我掉入了回调陷阱res.on 里面接收到的数据是data 里面如果放入 client.on('connect',functi ...这个修改函数就会报错. 'use strict'; var redis = require('redis'), RDS_PORT = 6379, //端口号 RDS_HOST = '127.0.0.1', //服务器IP //RDS_PWD = 'porschev',

数据元素文本增强(修改标准数据元素描述)

事务代码:CMOD 1. . 2. 3. 4. 5. 数据元素文本增强(修改标准数据元素描述),布布扣,bubuko.com