Changes for page Concurrency

Last modified by chrisby on 2024/06/02 15:15

From version 1.2
edited by chrisby
on 2023/11/26 19:12
Change comment: There is no comment for this version
To version 1.21
edited by chrisby
on 2024/01/20 13:29
Change comment: There is no comment for this version

Summary

Details

Page properties
Title
... ... @@ -1,1 +1,1 @@
1 -Concurrency (todo)
1 +Concurrency
Content
... ... @@ -1,76 +1,52 @@
1 -* When I/O is the bottleneck of your application, more threads will increase the performance in opposite to when CPU is the bottleneck.
2 -* Stress Testing: Checking the throughput of an application by sending a huge amount of requests and examining the response times.
3 -* Isolate concurrent code by putting it in a few separate classes.
4 -* Always consider the concept of execution paths: The amount of possible interleaving of instructions that are processed by at least two threads. For example, objects with mutable states could unintentionally cause different results doing the same operation twice.
5 -* Atomic operation = operation which can not be interrupted by other threads. But for unsynchronized processes threads can put instructions between two atomic operations.
6 -* `synchronized` prevents unintended side-effects.
7 -* Server-based locking is preferred over client-based locking.
8 - * Server-based locking: The class used takes care of internal locking, so the user has nothing else to worry about.
9 - * Client-based locking: User has to manually implement locking. This approach error prone and hard to maintain.
10 -* If there is no access to the server an adapter class can be used instead. Even better would be thread-save collections using extended interfaces.
11 -* As little synchronized code (`synchronized`) as possible should be used. And if, then only for small, critical code sections.
1 +Objects are abstractions of processing, **threads are abstractions of timing**.
12 12  
13 -### Prevent Deadlocks
3 +### Why Concurrency?
14 14  
15 -* Do this by making one of its four conditions impossible.
5 +* **Concurrency is a decoupling strategy**. The what is decoupled from the when.
6 +* **Concurrency is can improve the throughput and structure** of an application.
16 16  
17 -### Mutual Exclusion (Mutex)
8 +### Why Not Concurrency?
18 18  
19 -* Description:
20 - * When resources can't be used by mutual thread and
21 - * there are less resources than threads.
22 -* Solutions:
23 - * Use concurrently accessible resources like AtomicInteger.
24 - * Increase the number of resources until its greater or equal to the number of competing threads.
25 - * Check if every required resource is accessible before the task starts.
10 +* **Unclean**: It is hard to write clean concurrent code, and it is harder to test and debug.
11 +* **Design Changes**: Concurrency doesn't always improve performance behavior and but it always requires fundamental design changes.
12 +* **Extra Management**: Concurrency demands a certain amount of management effort, which degrades performance behavior and requires additional code.
13 +* **Complexity**: Proper concurrency is complex, even for simple problems.
14 +* **Unreproducible**: Concurrency bugs are usually not reproducible; therefore, they are often written off as one-time occurrences (cosmic rays, glitches, etc.) rather than treated as true defects, as they should be.
15 +* **Side-Effects**: When threads access out-of-sync data, incorrect results may be returned.
26 26  
27 -### Lock & Wait
17 +### Defensive Concurrency Programming
28 28  
29 -* Description:
30 - * Once a thread acquires a resource, it will not release the resource until it has acquired all of the other resources it requires and has completed its work.
31 -* Solutions:
32 - * Before reservation of a resource, check its accessibility.
33 - * If a resource is not accessible, release every resource and start from anew.
34 -* Dangers:
35 - * Starvation: A thread never achieves to reserve all required resources.
36 - * Livelock: Thread gets tangled up.→ This approach is always applicable but inefficient as it causes a bad performance.
19 +* **Single-Responsibility Principle**
20 + * **Separation of code**: Changes to concurrent code should not be mixed with changes to the rest of the code. Therefore, you should separate the source code of sequential and concurrent code.
21 + * **Separation of change**: Concurrent code has special problems that are different, and often more serious, than sequential code. This means that concurrent and sequential code should be changed separately, not within the same commit, or even within the same branch.
22 +* **Principle of Least Privilege**: Limit concurrent code to the resources it actually needs to avoid side effects. Minimize the amount of shared resources. Divide code blocks and resources into smaller blocks to apply more granular, and therefore more restrictive, resource access.
23 +* **Data Copies**: You can sometimes avoid shared resources by either working with copies of data and treating them as read-only, or by making multiple copies of the data, having multiple threads compute results on them, and merging those results into a single thread. It is often worth creating multiple objects to avoid concurrency problems.
24 +* **Independence**: Threads should be as independent as possible. Threads should not share their data or know anything about each other. Instead, they should prefer to work with their own local variables. Try to break data into independent subsets that can be processed by independent threads, possibly in different processes.
37 37  
38 -### No preemption
26 +### Basic Knowledge
39 39  
40 -* Description:
41 - * A thread is unable to steal a resources reserved by another thread.
42 -* Solution:
43 - * A thread is allowed to ask another thread to release all of its resources (including the required one) and starting from anew. This approach is similar to the 'Lock & Wait' solution but has a better performance.
28 +Before starting to write concurrent code, get familiar with the following basics:
44 44  
45 -### Circular Waiting / Deadly Embrace
30 +* **Libraries**: Use the thread-safe collections provided. Use non-blocking solutions if possible. Be aware multiple library classes are not thread safe.
31 +* **Concepts**: Mutual Exclusion, Deadlock, Livelock, Thread Pools, Semaphore, Locks, Race Condition, Starvation,
32 +* **Patterns**: Producer-consumer, Reader-Writer
33 +* **Algorithms**: Study common algorithms and their use in solutions. For example, the Dining Philosophers problem.
46 46  
47 -* Description:
48 - * When two or more threads require a resource which is already reserved by another of these threads.
49 - * Example:
50 - * Thread T1 has resource R1 and waits for R2 to be released.
51 - * Thread T2 has resource R2 and waits for R1 to be released.
52 -* Solution:
53 - * All threads reserve all resources in a the same order.
54 -* Problems:
55 - * The order of reservation doesn't necessarily have to be the same as the order of usage. This leads to inefficiencies like reserving a resource at the beginning which is just required at the end of the task.
56 - * Unnecessarily long locked resources.
57 - * Order can not always be specified.
35 +### Synchronized Methods
58 58  
59 -### Problems of testing multi-threaded methods
37 +Synchronized means that only one thread can access a method at a time to prevent side effects.
60 60  
61 -* Very tricky which is why concurrency should be avoided in the first place.
62 -* In general this requires a lot of iteration which makes it resource intensive.
63 -* The outcome is architecture dependent (OS, hardware) which introduced randomness and make the error detection unreliable.
39 +* **Avoid dependencies between synchronized methods**: In concurrent code, such dependencies, such as when one synchronized method calls another, can cause subtle bugs like deadlocks and performance issues.
40 +* **Avoid applying more than one method to a shared object.** If this is not possible, you have three options:
41 + * **Client-based locking**: The client locks the server, calls all the server methods, and then releases the lock.
42 + * **Server-based locking**: Create a method in the server that locks the server, calls all the methods, and then unlocks the server. A client can now safely call this new method.
43 + * **Adapted Server**: Create an intermediate component to perform the lock. This is a variant of server-based locking when the original server cannot be changed. Ideally, one would use thread-save collections and implements them behind extended interfaces.
44 +* **Server-based locking is preferred over client-based locking.** With server-based locking, the class used takes care of the internal locking, so the user has nothing else to worry about. With client-based locking, the user has to implement locking manually, which makes the approach error-prone and difficult to maintain.
45 +* **Keep synchronized sections small.** Locks are expensive because they add administrative overhead and delay. On the other hand, critical sections need to be protected. Critical sections are pieces of code that will only run correctly if they are not accessed by multiple threads at the same time. Keeping synchronized sections small avoids both problem. Only use it for small, critical code sections.
64 64  
65 -### Solution approaches for testing multi-threaded methods
47 +### Miscellaneous
66 66  
67 -* Monte-Carlo-Tests
68 - * Write flexible, adaptive tests.
69 - * Repeatedly run them on a test server and randomly vary the test settings.
70 - * If something fails, the code is defect and the applied settings should be logged.
71 - * Do this early to gain tests ASAP for your testing repertoire or CI-server.
72 -* Execute these tests on every platform over a long time to increase the probability that
73 - * the production code is correct or
74 - * the test code is bad.
75 -* Execute the tests on a computer using simulations of application loads when possible.
76 -* There are tools to test thread-based code like ConTest.
49 +* **Performance**: When a performance bottleneck is detected in an application, the cause can be I/O or CPU. Increasing the number of threads will show which of the two is the actual bottleneck, see [[this article|doc:Software Engineering.Testing.Enhance Test Execution Speed.WebHome]].
50 +* **Stress Testing**: A common type of test that determines the maximum throughput of an application by sending a large number of requests and examining the response times.
51 +* **Execution Paths**: Always consider the concept of different execution paths. The amount of possible interleaving of instructions that are processed by at least two threads. For example, objects with mutable states could unintentionally cause different results doing the same operation twice.
52 +* **Write Shutdown Code Early**: Shutting down an application requires the safe termination of all concurrent processes. Writing shutdown code is difficult. Writing shutdown code early is cheaper than writing it later. Study the available algorithms.