-
Notifications
You must be signed in to change notification settings - Fork 212
JyAttribute.getAttr significantly slow down during multi-threading #360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think JyAttribute can be adjusted such that read access can be unsynchronized. I suspect the blocking you observe is mainly (like 99%) from read access (correct me if I'm wrong). I'm preparing a PR to de-synchronize JyAttribute read-access. |
It's not generally true that only write access needs synchronisation. If a field is final (and initialised by one thread before it can be seen by any other) we're good.
What if a thread A reads |
The read/cache -> update -> write sequence is precisely the reason why write access will continue to be synchronized. However, this can be organized such that a concurrent read access finds a valid state at every point in time. The trade-off is that the concurrent read access might still get the "old" state because a slightly earlier write access has not yet finnished. In other words, in case of concurrent access, it will be undefined whether the old state or new state is read, but it will be one of them.
Since the |
Ah, I hadn't recognised this was yours originally. But it is documented, so I should have guessed. :) I have never entirely settled in my mind what guarantees we ought to give about concurrent access to objects we design. Currently I think that unmanaged concurrent access should not break an object at the Java level, but that the application threads should not then expect to see the same state. I think this is what you are aiming at. There are probably Python applications that work correctly in CPython only because of the inadvertent synchronisation brought about by the GIL, but I don't think they're ours to fix. By "the original synchronized block" above you mean whatever keeps the threads of the outer application from tripping over each other? It could be some other kind of lock taken before the object in question is accessed. It's a Java claim that uncontended access is cheap. If so, for the problem to be this significant, threads getting an attribute here are likely in real contention for a shared |
I'll admit this makes my head spin, but I think it contains the concepts for a little comment why your solution is ok. I was going to add what I thought the solution might be, but I think I'm still wrong. Concurrency is hard. -- Brian Goetz. (Let's go shopping. -- Barbie.) |
I mainly learned from http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html (once shared by you, thx!) the issue of possible reordering. From that doc I get that the reordering of assignment and object initialization is prevented for volatile fields in modern (not totally ancient, that is) Java. The desync of getAttr works based on that assumption. Re static methods: We wanted to move the |
Thanks Stewori and jeff5 for the quick reply.
Hope this helps. |
@newprogrammer101 That confirms that solving the read access should solve the problem. @jeff5 I think from the linked jls doc, 17.4.4 "A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread" and the induced x happens-before y relation The complexity of this matter makes it somewhat hard to believe that it actually works the way it is supposed to :) We'll see what tests say... |
@newprogrammer101 can you clone my branch https://github.com/Stewori/jython/tree/desync_JyAttribute_getAttr and check whether it solves the performance issue in your scenario? |
Hi, Stewori, appreciate for resolving the issue by changing synchronized to volatile to mitigate race condition issue. It looks good to me. Will you publish a new Jython version to include this commit? |
As discussed in the PR, this change is too theoretic and, given our near-zero experience with this kind of synchronization tuning, too experimental to be deployed into master without further testing. I wrote a consistency and stress test for the implementation with help of AI (that was actually an experiment on its own right - I could have done it without AI and the code needed several adjustments, but I wanted to see if it can actually save time). The test is currently a standalone based on a mocked PyObject, but with original JyAttribute code (I told the AI it's a multi-threaded stress test for a custom Dict implementation, hence the Also, it would be good if you could confirm that the PR does actually solve the performance issue in your setting before it is integrated into master. If a different approach should be required, the trial-and-error-development should not take place in master. |
Hi Stewori, thanks for follow-up. I manually modified the Jython dependency locally with your change and can see improvement on latency. If my understanding is correct, you want to perform more stress test before commit this change to the master branch. If so, there is no urgency at the moment. Once the new version of Jython released, I will ask my company's Ops team to import the latest change. Thank you. |
Hi Stewori, do we have any plan when do we want to merge the commit to the main pipeline as the new version? From my side, I can confirm by changing synchronized keyword to volatile can significantly reduce latency as there is no Lock anymore. Thank you. |
Another concern is I notice Jython uses PrintStream.flush often, but according to https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/io/PrintStream.java#L402, looks like it also has synchronized issue that might be no good for multi-threading. |
Concurrency is hard to reason about successfully, so the test is important. (Not the test that it goes faster: the test that it is still correct.) You can see above that @Stewori has done some work towards a test and, if it passes, it would be nice to get this into a 2.7.5 beta. The link to The stream output from Jython is complex because of the uneasy relationship amongst character output in Java, the byte oriented streams in Python, and terminal encoding (a real mess on Windows). ISTR frequent flushing was necessary for data to emerge in the right order. |
Hi, @jeff5 , thanks for reply. Not sure if thread-pool to create multi-instance might help as the sychronized key word usually lock the same instance (As long as it is a IO operation CPU can be used for other thread). |
Uh oh!
There was an error while loading. Please reload this page.
I have a service deployed on AWS and use CodeGuru to analyze the performance. I have found when high concurrency >20TPS,
JyAttribute.getAttr
makes CPU in 95% of BLOCKED time. There was an issue in 2016, but I do not think it got resolved completely as there is still a Synchronized(ob) https://bugs.jython.org/issue2452.This brought a huge latency impact due to synchronized. I am looking for a way to improve the performance during high-concurrency to avoid this kinds of lock. Thanks.
The text was updated successfully, but these errors were encountered: