Синхронизируемые и локальные копии переменных

Python, 446 байтов. Все строки менее чем 80 столбцов, черт возьми. Это решение Paul Fisher с кодированием тонких настроек почти на каждой строке, вниз от его 488-байтовой версии; он с тех пор отжат еще несколько байтов, и я признаю. Пойдите голосование за его ответ!

g=lambda n:["zero"," ".join(w(n,0))][n>0]
w=lambda n,l:w(n//m,l+1)+[e,z[n%m//100]+["hundred"]][n%m//100>0]+\
(p("twen thir fo"+r,"ty")[n%100//10-2]+z[n%10]if n%100>19 else z[n%100])+\
[e,k[l]][n%m>0]if n else e
p=lambda a,b:[[i+b]for i in a.split()]
e=[];r="r fif six seven eigh nine";m=1000
k=[e,["thousand"]]+p("m b tr quadr quint","illion")
z=[e]+p("one two three four five six seven eight nine ten eleven twelve","")+\
p("thir fou"+r,"teen")

история стала сложной. Я запустил с незапутываемого кода ниже, который поддерживает отрицательные числа и проверку диапазона плюс тире в некоторых числах для лучшего английского языка:

>>> n2w(2**20)
'one million forty-eight thousand five hundred seventy-six'

def n2w(n):
    if n < 0:  return 'minus ' + n2w(-n)
    if n < 10: return W('zero one two three four five six seven eight nine')[n]
    if n < 20: return W('ten eleven twelve',
                        'thir four fif six seven eigh nine',
                        'teen')[n-10]
    if n < 100: 
        tens = W('', 'twen thir for fif six seven eigh nine', 'ty')[n//10-2]
        return abut(tens, '-', n2w(n % 10))
    if n < 1000:
        return combine(n, 100, 'hundred')
    for i, word in enumerate(W('thousand', 'm b tr quadr quint', 'illion')):
        if n < 10**(3*(i+2)):
            return combine(n, 10**(3*(i+1)), word)
    assert False

def W(b, s='', suff=''): return b.split() + [s1 + suff for s1 in s.split()]
def combine(n, m, term): return abut(n2w(n // m) + ' ' + term, ' ', n2w(n % m))
def abut(w10, sep, w1):  return w10 if w1 == 'zero' else w10 + sep + w1

Тогда я сжал его приблизительно к 540 байтам через (плохо мне знакомую) путаницу, и Paul Fisher нашел более короткий алгоритм (отбрасывающий тире) наряду с некоторым удивительно ужасным Python, кодирующим приемы. Я украл приемы кодирования для перехода 508 (который все еще не победил). Я пытался перезапустить новый с новым алгоритмом, который был неспособен избить Fisher. Наконец вот тонкая настройка его кода. Уважение!

запутываемый код был протестирован против чистого кода, который был проверен глазным яблоком на наборе случаев.

13
задан Epsilon Prime 3 November 2009 в 22:45
поделиться

4 ответа

The reason this is flagged as a problem is because synchronizing on local variables is usually a bad idea.

If the object returned by someGlobalInstance.getMap() is always the same, then the synchronized block does in fact use that quasi-global objects monitor and the code produces the expected result.

I also agree with the suggestion to use a synchronized wrapper, if you only need to synchronize the get()/put() calls and don't have any bigger synchronized blocks. But make sure that the Map is only accessed via the wrapper or you'll have another chance for bugs.

Also note that if someGlobalInstance.getMap() does not return the same object all the time, then even your second code example will not work correctly, it could even be worse than your original code since you could synchronize on a different object than the one you call get() on.

12
ответ дан 1 December 2019 в 22:57
поделиться

I think the code could be sound, depending on what the getMap() method does. If it keeps a reference to an instance that has to be shared between threads it makes sense. The warning is irrelevant since the local variable is not initialized locally.

4
ответ дан 1 December 2019 в 22:57
поделиться

I think it would be better to use synchronized wrapper for your map

2
ответ дан 1 December 2019 в 22:57
поделиться

Алекс прав в том, что добавление синхронизированной оболочки путем вызова Collections.synchronizedMap (Map) является здесь типичным подходом. Однако, если вы воспользуетесь этим подходом, все равно могут возникнуть ситуации, когда вам потребуется синхронизация на блокировке Map ; например, при итерации по карте.

Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<String, String>());

// Synchronized on map to prevent ConcurrentModificationException whilst iterating.
synchronized (syncMap) {
  for (Map.Entry<String, String> entry : syncMap.entrySet()) {
    // Do work
  }
}

В вашем примере предупреждение от IDEA можно проигнорировать, поскольку очевидно, что ваша локальная переменная: map извлекается откуда-то еще ( someGlobalInstance ), а не создается внутри метода, и поэтому потенциально может быть доступен из других потоков.

2
ответ дан 1 December 2019 в 22:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: